How to use the SVG Renderer
The SVG Renderer allows direct access to the Highcharts rendering layer in order to draw primitive shapes like circles, rectangles, paths or text directly on a chart, or independent from any chart. It represents a JavaScript wrapper object for SVG.
Relevant API documentation
Standalone use
As a standalone API, the Highcharts renderer is a handy abstraction to drawing vector graphics in the browser.
const renderer = new Highcharts.SVGRenderer(
document.getElementById('container'),
600,
400
);
Once the renderer is instanciated, it can be used to render primitive shapes
onto the SVG. Common elements are rect
, circle
, path
, label
and text
,
along with groups g
and other methods. See the class
reference
for the full list and live demos.
renderer.circle(100, 100, 50).attr({
fill: 'red',
stroke: 'black',
'stroke-width': 1
}).add();
renderer.text('Hello world', 200, 100).attr({
rotation: 45
}).css({
fontSize: '16pt',
color: 'green'
}).add();
Bringing it to life
All generated elements can be updated dynamically, either immediately through the attr function, or by animation through the animate function. Check out this demo for some simple elements with animation:
Putting it to use on a chart
While freeform drawing capabilities are a nice feature, the renderer gets really useful when it can be used for custom graphics on top of a chart.
Each Chart
instance has its own reference to a renderer . This can be accessed to draw
shapes directly onto the chart’s SVG.
The best way to hook custom drawings into the chart rendering process, is to listen for the chart.events.render event. This event is good for the purpose because it fires both on the first render, and subsequently every time the chart redraws as a consequence of either updating data, options or the container size. More on that below.
The render
event handler can be assigned in two different ways.
- Add it to the options structure, chart.events.render . This applies per instance.
- Alternatively, add it the Chart class, so it will apply to all instances.
Highcharts.addEvent(Highcharts.Chart, 'render', eventHandler)
. This method is more modular and invites to keeping the options structure clean, but requires that other options, like for example chart.className , be used to identify individual charts. Read more about addEvent and see the addEvent and render demo .
Adding responsive shapes
Let’s take a closer look at how we can create a custom annotation, and keep it in place as we change the size of the chart.
Check out the demo for renderer on a chart .
In this case the annotation is closely tied to this specific chart, so we want
to add the render
event handler to the options structure. The chart we are
building is a column chart showing precipitation. For the sake of the demo
we want to show a bracket and a text that draw attention to the usually rainful
autumn months. Moreover, this needs to scale up and down because the chart is
responsive and reacts to the size of the containing div.
On the -first call- to the render
event, we create the element.
let isNew = false;
if (!this.autumnBracket) {
this.autumnBracket = this.renderer.path()
.attr({
stroke: '#333333',
'stroke-width': 1
})
.add();
this.autumnText = this.renderer.text('Autumn months')
.attr({
'text-anchor': 'middle'
})
.css({
fontStyle: 'italic'
})
.add();
isNew = true;
}
Note that we haven’t supplied the actual path definition yet, and we have not
set the x and y positions of the text. What we do, is to register the elements
directly on the Chart instance (this
), so that subsequent render events will
pick them up and reuse them instead of creating new ones. Also note that we
define a flag, isNew
, that we will use below.
After doing some math to determine exactly where to put the elements, we do the actual placement:
this.autumnBracket[isNew ? 'attr' : 'animate']({
d: [
['M', left, top + 10],
['L', left, top],
['L', right, top],
['L', right, top + 10]
]
});
this.autumnText[isNew ? 'attr' : 'animate']({
x: (right + left) / 2,
y: top - 5
});
This positioning runs both on the initial draw, and on subsequent redraws. The
only difference is that we use the isNew
flag to decide if the element was
newly created. If isNew
is true, we run the attr
function, because we don’t
want an animation from a [0, 0] position. If isNew
is false, it means the
element was created in a previous render call, which in turn means that we want
a smooth animation into the new position along with other native chart elements
that are animated.
See the full example here, and notice how it repositions if you change the viewport size:
Positioning items on the chart
In the demo above we used Point.pos() to decide where to draw our annotation. Some other positioning properties are handy when placing custom drawings on the chart:
- Chart.plotLeft and Chart.plotTop reflect the position of the plot area.
- Chart.plotWidth and Chart.plotHeight reflect the size of the plot area, and can be combined with the previous to find the right and bottom positions.
- Axis.pos and
Axis.len
usually are the same as the above, because the axes usually fill the full extent
of the plot area. The exception is when the axis is specifically positioned
using
left
ortop
options. - The Series.center property is available on circular series types like pie and sunburst.