score: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


Related Query

More Query from same tag