2

I am a newbie in data visualisation. I would like to tweak around a pie chart to come up with an arrow ring chart like in the image below. Thanks for your help

Arrow Ring Chart

Gordon
  • 19,811
  • 4
  • 36
  • 74
  • Here's something I [built once](https://bl.ocks.org/larsenmtl/1d4b242e86bfde14490ba3ea82261958). – Mark Oct 22 '18 at 11:24
  • For D3, [this](https://stackoverflow.com/a/41194980/7106086) answer is related (arc heads as arrows) and [this](https://bl.ocks.org/Andrew-Reid/51d2665a976266abbaa62eae1ba80cdc) refines linked answer and allows indentation of the arc tails too. – Andrew Reid Oct 22 '18 at 15:16
  • Thank you @AndrewReid...The refine works fine for me – Bryan Nahabwe Oct 23 '18 at 13:30

1 Answers1

3

Highcharts pie chart can be customized to the arrow ring chart. It requires a little custom code but can be done. I prepared you an example of a donut chart where I added a custom symbol (more about custom symbols here), additionally, I overwritten H.SVGRenderer.prototype.arc to use my custom symbol instead of the default one (arc in a pie chart).

So what you have to add there is an arrow ring path (instead of arc) which is the main issue to solve. Highcharts will use this symbol to plot each point (arrow ring). Try to add an additional path to the existing arc path of the beginning and end of each point. It is a little tricky because you will have to calculate extreme points of each slice (chart point) and angle to render an appropriate path (beginning or end arrow).

Check the demo I posted you below and try to change arc array there to find out what I'm talking about. Check also the description of Highcharts.SVGRenderer path method description to know how to create your custom arrow paths.

Demo: jsfiddle

HTML:

<script src="https://code.highcharts.com/highcharts.js"></script>
<div id="container"></div>

JS:

// Define a custom symbol path
Highcharts.SVGRenderer.prototype.symbols.arcArrow = function(x, y, w, h, options) {
  var start = options.start,
    pick = Highcharts.pick,
    defined = Highcharts.defined,
    rx = options.r || w,
    ry = options.r || h || w,
    proximity = 0.001,
    fullCircle =
    Math.abs(options.end - options.start - 2 * Math.PI) <
    proximity,
    end = options.end - proximity,
    innerRadius = options.innerR,
    open = pick(options.open, fullCircle),
    cosStart = Math.cos(start),
    sinStart = Math.sin(start),
    cosEnd = Math.cos(end),
    sinEnd = Math.sin(end),
    // Proximity takes care of rounding errors around PI (#6971)
    longArc = options.end - start - Math.PI < proximity ? 0 : 1,
    arc;

  // Here you can define your arrows path instead of arc
  // Try to add additional code to beggining and end of existing arc

  arc = [
    'M',
    x + rx * cosStart,
    y + ry * sinStart,
    'A', // arcTo
    rx, // x radius
    ry, // y radius
    0, // slanting
    longArc, // long or short arc
    1, // clockwise
    x + rx * cosEnd,
    y + ry * sinEnd
  ];

  if (defined(innerRadius)) {
    arc.push(
      open ? 'M' : 'L',
      x + innerRadius * cosEnd,
      y + innerRadius * sinEnd,
      'A', // arcTo
      innerRadius, // x radius
      innerRadius, // y radius
      0, // slanting
      longArc, // long or short arc
      0, // clockwise
      x + innerRadius * cosStart,
      y + innerRadius * sinStart
    );
  }

  arc.push(open ? '' : 'Z'); // close
  return arc;
};
if (Highcharts.VMLRenderer) {
  Highcharts.VMLRenderer.prototype.symbols.arcArrow = Highcharts.SVGRenderer.prototype.symbols.arcArrow;
}


(function(H) {
  H.SVGRenderer.prototype.arc = function(x, y, r, innerR, start, end) {
    var arc,
      isObject = H.isObject,
      options;

    if (isObject(x)) {
      options = x;
      y = options.y;
      r = options.r;
      innerR = options.innerR;
      start = options.start;
      end = options.end;
      x = options.x;
    } else {
      options = {
        innerR: innerR,
        start: start,
        end: end
      };
    }

    // Arcs are defined as symbols for the ability to set
    // attributes in attr and animate
    arc = this.symbol('arcArrow', x, y, r, r, options);
    arc.r = r; // #959
    return arc;
  }
})(Highcharts);


Highcharts.chart('container', {
  series: [{
    type: 'pie',
    innerSize: '70%',
    data: [
      ['Chrome', 58.9],
      ['Firefox', 13.29],
      ['Internet Explorer', 13],
      ['Edge', 3.78],
      ['Safari', 3.42],
      {
        name: 'Other',
        y: 7.61,
        dataLabels: {
          enabled: false
        }
      }
    ]
  }]
});

I hope it will be helpful for you. If you will have any troubles with it or my explanation is too complicated do not hesitate to ask me.

Wojciech Chmiel
  • 7,302
  • 1
  • 7
  • 16