绘图区域外的高图注释未正确放置

时间:2018-11-30 22:59:10

标签: highcharts

我想在y轴上但在绘图区域之外放置注释。这些应与连接器(标注)放置在与PlotLines相同的高度。

但是,那里的设置无法正常工作(请参见图片-红色)。对齐方式应为水平“右”和垂直“居中”。这样右侧的连接器在轴上。

screenshot

annotations: [{
labelOptions: {
  align: 'right',
  verticalAlign: 'middle',
  //distance: 0,
  overflow: 'allow',
  crop: false
},
labels: [{
  point: {
    x: -6,
    y: 273,
    yAxis: 0
  },
  format: 'wrong right middle'
}]
}]

距离给出错误的结果。如果激活此选项,则注释将跳到另一个位置。它似乎只适用于垂直位移。 我当前的解决方法是,将标注添加为CSS样式。但这不是要走的路。

https://jsfiddle.net/xreality/dskfv986/

谢谢 迈克

1 个答案:

答案 0 :(得分:1)

Highcharts annotations use callout symbol (Highcharts.SVGRenderer.prototype.symbols.callout) by default which is not designed for this usage. However, you can modify it so that it fits your needs. Check my wrap posted below and demo with it.

Wrapper on Highcharts.SVGRenderer.prototype.symbols.callout method:

(function(H) {
  H.SVGRenderer.prototype.symbols.callout = function(x, y, w, h, options) {
    var arrowLength = 6,
      halfDistance = 6,
      r = Math.min((options && options.r) || 0, w, h),
      safeDistance = r + halfDistance,
      anchorX = options && options.anchorX,
      anchorY = options && options.anchorY,
      path;

    path = [
      'M', x + r, y,
      'L', x + w - r, y, // top side
      'C', x + w, y, x + w, y, x + w, y + r, // top-right corner
      'L', x + w, y + h - r, // right side
      'C', x + w, y + h, x + w, y + h, x + w - r, y + h, // bottom-rgt
      'L', x + r, y + h, // bottom side
      'C', x, y + h, x, y + h, x, y + h - r, // bottom-left corner
      'L', x, y + r, // left side
      'C', x, y, x, y, x + r, y // top-left corner
    ];

    // Anchor on right side
    if (anchorX && anchorX > w) {

      // Chevron
      if (
        anchorY > y + safeDistance &&
        anchorY < y + h - safeDistance
      ) {
        path.splice(13, 3,
          'L', x + w, anchorY - halfDistance,
          x + w + arrowLength, anchorY,
          x + w, anchorY + halfDistance,
          x + w, y + h - r
        );

        // Simple connector
      } else {
        path.splice(13, 3,
          'L', x + w, h / 2,
          anchorX, anchorY,
          x + w, h / 2,
          x + w, y + h - r
        );
      }

      // Anchor on left side
    } else if (anchorX && anchorX < 0) {

      // Chevron
      if (
        anchorY > y + safeDistance &&
        anchorY < y + h - safeDistance
      ) {
        path.splice(33, 3,
          'L', x, anchorY + halfDistance,
          x - arrowLength, anchorY,
          x, anchorY - halfDistance,
          x, y + r
        );

        // Simple connector
      } else {
        path.splice(33, 3,
          'L', x, h / 2,
          anchorX, anchorY,
          x, h / 2,
          x, y + r
        );
      }

    } else if ( // replace bottom
      anchorY &&
      anchorY > h &&
      anchorX > x + safeDistance &&
      anchorX < x + w - safeDistance
    ) {
      path.splice(23, 3,
        'L', anchorX + halfDistance, y + h,
        anchorX, y + h + arrowLength,
        anchorX - halfDistance, y + h,
        x + r, y + h
      );

    } else if ( // replace top
      anchorY &&
      anchorY < 0 &&
      anchorX > x + safeDistance &&
      anchorX < x + w - safeDistance
    ) {
      path.splice(3, 3,
        'L', anchorX - halfDistance, y,
        anchorX, y - arrowLength,
        anchorX + halfDistance, y,
        w - r, y
      );
    } else { // add to support right arrows
        path.splice(13, 3,
          'L', x + w, anchorY - halfDistance,
          x + w + arrowLength, anchorY,
          x + w, anchorY + halfDistance,
          x + w, y + h - r
        );
    }

    return path;
  }
})(Highcharts);

Demo: https://jsfiddle.net/BlackLabel/0eydz6q3/

EDIT

For annotations that are dynamically added, we can use chart.events.render to get each element dimensions using SVGElement.getBBox() method and calculate appropriate offsets using particular annotation width and height. Nextly we have to remove the old annotations using chart.removeAnnotations('id') method and add new ones (with updated distance and x position) using chart.addAnnotations(newOptions). Check the demo posted below.

  chart: {
    events: {
      render: function() {
        var chart = this,
          annotations = chart.annotations[0],
          options = annotations.userOptions,
          labels = options.labels,
          arrowWidth = 6,
          bbox;

        labels.forEach(function(label, i) {
          if (label.point.x === 0) {
            bbox = annotations.labels[i].getBBox();
            label.point.x = -(bbox.width / 2 + arrowWidth);
            label.distance = -bbox.height / 2;
          }
        });

        chart.removeAnnotation('annotations-id');
        chart.addAnnotation(options);
      }
    }
  }

Demo:
https://jsfiddle.net/BlackLabel/wf8q1odj/1/

Api reference:
https://api.highcharts.com/class-reference/Highcharts.SVGElement#getBBox https://api.highcharts.com/class-reference/Highcharts.Chart#removeAnnotation https://api.highcharts.com/class-reference/Highcharts.Chart#addAnnotation