highcharts - chart names for multiple pie chart series in one chart - highcharts

I need to display multiple pie charts that are all related to the same data. As such I want them all to be part of the same chart and implement them as individual series.
This all works no problems until I tried to put labels/titles over each individual pie chart. It seems that I can only have a title over the entire group. See jsfiddle
Is there any way to have the titles over each chart?
See above jsfiddle for example

I encountered the same problem, and found this solution via highcharts support forum :
http://highcharts.uservoice.com/forums/55896-general/suggestions/3073133-pie-title
The Highcharts dude has written a plugin that you can see working on the following jsfiddle : http://jsfiddle.net/highcharts/tnSRA/
I have copy-pasted this plugin in a highcharts-plugins.js file that I included in my website, works like a charm!
Here's the plugin code :
/**
* Pie title plugin
* Last revision: 2012-12-21
*/
(function (Highcharts) {
Highcharts.wrap(Highcharts.seriesTypes.pie.prototype, 'render', function (proceed) {
var chart = this.chart,
center = this.center || (this.yAxis && this.yAxis.center),
titleOption = this.options.title,
box;
proceed.call(this);
if (center && titleOption) {
box = {
x: chart.plotLeft + center[0] - 0.5 * center[2],
y: chart.plotTop + center[1] - 0.5 * center[2],
width: center[2],
height: center[2]
};
if (!this.title) {
this.title = this.chart.renderer.label(titleOption.text)
.css(titleOption.style)
.add()
.align(titleOption, null, box);
} else {
this.title.align(titleOption, null, box);
}
}
});
}(Highcharts));
And this is how you configure your title (put this in your series elements) :
title: {
// align: 'left',
// x: 0
// style: { color: XXX, fontStyle: etc }
text: '<b>Pie 1</b><br>Subtext',
verticalAlign: 'top',
y: -40
},

To further improve on this, the code below correctly handles left, center, and right justification for the titles. See fiddle at http://jsfiddle.net/9y4Lj4yr/ for an example.
/**
* Pie title plugin
* Last revision: 2015-5-20
*/
(function (Highcharts) {
Highcharts.wrap(Highcharts.seriesTypes.pie.prototype, 'render', function (proceed) {
var chart = this.chart,
center = this.center || (this.yAxis && this.yAxis.center),
titleOption = this.options.title,
box;
proceed.call(this);
if (center && titleOption) {
box = {
x: chart.plotLeft + center[0] - 0.5 * center[2],
y: chart.plotTop + center[1] - 0.5 * center[2],
width: center[2],
height: center[2]
};
if (!this.title) {
this.title = this.chart.renderer.label(titleOption.text)
.css(titleOption.style)
.add()
}
var labelBBox = this.title.getBBox();
if (titleOption.align == "center")
box.x -= labelBBox.width/2;
else if (titleOption.align == "right")
box.x -= labelBBox.width;
this.title.align(titleOption, null, box);
}
});
} (Highcharts));

You can use renderer which allows to add text in any place.
http://api.highcharts.com/highcharts#Renderer.text()

Improving on Vincent's answer. This is how I used it for simple Text titles.
extendHighcharts = function(){
Highcharts.wrap(Highcharts.seriesTypes.pie.prototype, 'render', function (proceed) {
//Clear the title if added previously
//if your chart data does not change, this reference storage for removal can be left out
if(this.chart.subChartTitleElement){
this.chart.subChartTitleElement[this.id].destroy();
}
proceed.call(this);
if (this.center && this.options.title) {
//first, add the title, at center or anywhere, we need the container width to center it
this.chart.subChartTitleElement[this.id] = this.chart.renderer.text(this.options.title.text,this.center[0],this.center[1]);
this.chart.subChartTitleElement[this.id].css(this.options.title.style)
this.chart.subChartTitleElement[this.id].add();
//Center the title using the container(Bounding Box = BBox) width
var xCenter = this.chart.plotLeft + this.center[0] - (this.chart.subChartTitleElement[this.id].getBBox().width/2),
yCenter = this.chart.plotTop + this.center[1] - 0.6 * this.center[2];
this.chart.subChartTitleElement[this.id].attr(
{
x:xCenter,
y:yCenter
}
);
}
});
}
USAGE
this.chart.addSeries({
type: 'pie',
name: 'pie_chart_1',
data: pieChartData,
center: ['80%','25%'],
size: '35%',
showInLegend: false,
dataLabels: {
enabled: false
},
//this part adds the relevant information
title: {
text:'Pie Chart Title',
verticalAlign: 'top',
y: -40
},
id:'a_unique_id_or_name'
});

Related

Add dataLabels to solid guage

How can i add data label in front of each point in solid gauge chart. I am try to achieve something like this
Thanks
You can add custom data labels in render event, for example:
chart: {
...,
events: {
render: function() {
var dataLabels = ['Custom DL1', 'Custom DL2', 'Custom DL3'],
chart = this,
series = chart.series;
dataLabels.forEach(function(dl, i) {
if (!series[i].customDL) {
series[i].customDL = chart.renderer.text(dl)
.attr({
zIndex: 10
})
.add(series[i].group);
}
series[i].customDL.translate(
chart.chartWidth / 2 + 10,
chart.plotHeight / 2 - series[i].points[0].shapeArgs.innerR -
(series[i].points[0].shapeArgs.r - series[i].points[0].shapeArgs.innerR) / 2
);
});
}
}
}
Live demo: https://jsfiddle.net/BlackLabel/c5eq2htg/
API Reference:
https://api.highcharts.com/highcharts/chart.events.render
https://api.highcharts.com/class-reference/Highcharts.SVGRenderer#text

Highcharts - sync crosshair of charts with different width

I try to get a synced crosshair for multiple highcharts each with a different width.
For know the crosshair is syncing on the position of the cursor and not on the position of the point / the xAxis value (which would be prefered). Can anyone give me a hint how to achieve this?
I have changed the synced charts example in the following fiddle:
https://jsfiddle.net/3mn4x8uy/
The chart creation:
$.each(activity.datasets, function (i, dataset) {
// Add X values
dataset.data = Highcharts.map(dataset.data, function (val, j) {
return [activity.xData[j], val];
});
$('<div class="chart">')
.appendTo('#container')
.highcharts({
chart: {
marginLeft: 40+i*100, // make different width for each chart
spacingTop: 20,
spacingBottom: 20
},
sync code
$('#container').bind('mousemove touchmove touchstart', function (e) {
var chart,
point,
i,
event;
for (i = 0; i < Highcharts.charts.length; i = i + 1) {
chart = Highcharts.charts[i];
// Find coordinates within the chart
event = chart.pointer.normalize(e.originalEvent);
// Get the hovered point
point = chart.series[0].searchPoint(event, true);
if (point) {
point.highlight(e);
}
}
});
Thanks
Here you can find an example how to synchronize multiple charts based on xAxis value: http://jsfiddle.net/BlackLabel/udtkgs9m/
The code to sync a Plotline over multiple Charts:
function syncronizeCrossHairs(chart) {
var container = jQuery(chart.container),
offset = container.offset(),
x, y;
container.mousemove(function(evt) {
x = evt.clientX - chart.plotLeft - offset.left;
y = evt.clientY - chart.plotTop - offset.top;
var val = chart.xAxis[0].translate(x, true);
Highcharts.each(Highcharts.charts, function (act_chart) {
var xAxis = act_chart.xAxis[0];
xAxis.removePlotLine("myPlotLineId");
xAxis.addPlotLine({
value: val,
width: 1,
color: 'red',
//dashStyle: 'dash',
id: "myPlotLineId"
});
});
});
}

Highchart World map with pie

Here is the highchart demo of map with pie charts.
US map with pie charts
But this map is only for US. Here is my js fiddle.
World wide map with pie charts
// Add the pies after chart load, optionally with offset and connectors
Highcharts.each(chart.series[0].points, function (state) {
if (!state.id) {
return; // Skip points with no data, if any
}
var pieOffset = state.pieOffset || {},
centerLat = parseFloat(state.properties.latitude),
centerLon = parseFloat(state.properties.longitude);
// Add the pie for this state
chart.addSeries({
type: 'mappie',
name: state.id,
zIndex: 6, // Keep pies above connector lines
sizeFormatter: function () {
var yAxis = this.chart.yAxis[0],
zoomFactor = (yAxis.dataMax - yAxis.dataMin) /
(yAxis.max - yAxis.min);
return Math.max(
this.chart.chartWidth / 45 * zoomFactor, // Min size
this.chart.chartWidth / 11 * zoomFactor * state.sumVotes / maxVotes
);
},
tooltip: {
// Use the state tooltip for the pies as well
pointFormatter: function () {
return state.series.tooltipOptions.pointFormatter.call({
id: state.id,
hoverVotes: this.name,
demVotes: state.demVotes,
repVotes: state.repVotes,
libVotes: state.libVotes,
grnVotes: state.grnVotes,
sumVotes: state.sumVotes
});
}
},
data: [{
name: 'Democrats',
y: state.demVotes,
color: demColor
}, {
name: 'Republicans',
y: state.repVotes,
color: repColor
}, {
name: 'Libertarians',
y: state.libVotes,
color: libColor
}, {
name: 'Green',
y: state.grnVotes,
color: grnColor
}],
plotOptions: {
pie: {
center: [state.plotX+400, state.plotY]
}
}
}, false);
// Draw connector to state center if the pie has been offset
/* if (pieOffset.drawConnector !== false) {
var centerPoint = chart.fromLatLonToPoint({
lat: centerLat,
lon: centerLon
}),
offsetPoint = chart.fromLatLonToPoint({
lat: centerLat + (pieOffset.lat || 0),
lon: centerLon + (pieOffset.lon || 0)
});
chart.series[2].addPoint({
name: state.id,
path: 'M' + offsetPoint.x + ' ' + offsetPoint.y +
'L' + centerPoint.x + ' ' + centerPoint.y
}, false);
} */
});
I want to show map world wide map where each pie represent a country. Everything is working fine but world.js file dont have lat and long values.due to which i am facing positon issue of pie on each location.i tried using plotx and ploty .but it doesnt works. So is there any way to show pie axactly on the country area the way it is working US map?
You can use plotX & plotY properties of the region when it doesn't have the lat & lon defined.
Replace these two pieces of code:
plotOptions: {
pie: {
center: [state.plotX+400, state.plotY]
}
}
// Handle lat/lon support
if (options.center.lat !== undefined) {
var point = chart.fromLatLonToPoint(options.center);
options.center = [
chart.xAxis[0].toPixels(point.x, true),
chart.yAxis[0].toPixels(point.y, true)
];
}
with these ones:
center: {
plotX: state.plotX,
plotY: state.plotY
}
// Replace lat/lon with plotX/plotY
if (options.center.plotX !== undefined) {
options.center = [options.center.plotX, options.center.plotY];
}
By the way: using plotOptions inside series options is not valid. plotOptions should be placed in the top level of the chart options structure. Here's more info on that: https://api.highcharts.com/highcharts/plotOptions
Live demo: https://jsfiddle.net/BlackLabel/k5mdL6vn/

Breadcrumbs in Highcharts large treemap [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I have a requirement to show breadcrumbs in High charts large tree map as we drill down the level.
As we drill down, need to show the name in the breadcrumbs and user should be able to navigate.
Something similar to the Breadcrumbs in highchart-treemap
But I could not find any solution. Let me know how to achieve this
Drilldown events are not available for a treemap series. Instead you can use point click event for displaying/destroying breadcrumb element - a label.
Disable drill up button:
Highcharts.seriesTypes.treemap.prototype.showDrillUpButton = function () {
this.drillUpButton = {
destroy: function () {}
}
}
Function for creating a breadcrumb element can look like this:
function makeNode(id, name, series, prev) {
const chart = series.chart
const node = {
id,
name
}
let x = chart.plotLeft
if (prev) {
const { width, height, y } = prev.element.getBBox()
x = width + prev.x + 10
node.prev = prev
prev.next = node
prev.element.attr({
anchorX: x,
anchorY: chart.plotTop - 20 + height / 2
})
}
node.destroyNext = function () {
const next = this.next
if (next) {
next.destroyNext()
next.element.destroy()
delete this.next
delete chart.bread[next.id]
}
}
const element = node.element = chart.renderer.label(name, x, chart.plotTop - 20, 'callout').attr({
fill: '#FFFFEF',
stroke: 'gray',
'stroke-width': 2,
padding: 5,
r: 5,
zIndex: 10
}).add()
element.on('click', () => {
node.destroyNext()
node.element.attr({
anchorX: undefined,
anchorY: undefined
})
if (chart.series[0].rootNode !== '') series.drillToNode(id)
})
node.x = x
return node
}
Call that function on chart load:
chart: {
events: {
load: function() {
this.bread = {
'': makeNode('', this.series[0].name, this.series[0])
}
}
}
},
and on point click event:
plotOptions: {
series: {
point: {
events: {
click: function(e) {
const hasChildren = !!this.node.childrenTotal
if (hasChildren) {
const bread = this.series.chart.bread
bread[this.id] = makeNode(this.id, this.name, this.series, bread[this.node.parent])
}
}
}
}
}
},
Example and output
http://jsfiddle.net/z0zc1btk/

How to enable y-axis panning while zoom in highcharts?

I want to move in Y-Axis while i am in zoom in charts
Right now i am able to move on X-Axis while zooming
Bellow is the code for panning
chart: {
renderTo: 'container1',
type: 'column',
zoomType: 'xy',
panning: true,
panKey: 'shift',}
Any help would be appreciated
Possible solutions:
You could set vertical scrollbars in Highstock.
yAxis: {
scrollbar: {
enabled: true
}
},
Article: http://www.highcharts.com/news/224-scrollbars-for-any-axis
Demo: http://jsfiddle.net/gh/get/jquery/1.7.2/highcharts/highcharts/tree/master/samples/stock/yaxis/scrollbar/
Use a wrapper code (included below) based on the plugin suggested by Barbara that allows zooming (xy) and panning (xy).
The wrapper code:
(function (H) {
H.wrap(H.Chart.prototype, 'pan', function (proceed) {
var chart = this,
hoverPoints = chart.hoverPoints,
doRedraw,
e = arguments[1],
each = H.each;
// remove active points for shared tooltip
if (hoverPoints) {
each(hoverPoints, function (point) {
point.setState();
});
}
var mousePosX = e.chartX,
mousePosY = e.chartY,
xAxis = chart.xAxis[0],
yAxis = chart.yAxis[0],
startPosX = chart.mouseDownX,
startPosY = chart.mouseDownY,
halfPointRangeX = (xAxis.pointRange || 0) / 2,
halfPointRangeY = (yAxis.pointRange || 0) / 2,
extremesX = xAxis.getExtremes(),
newMinX = xAxis.toValue(startPosX - mousePosX, true) + halfPointRangeX,
newMaxX = xAxis.toValue(startPosX + chart.plotWidth - mousePosX, true) - halfPointRangeX,
extremesY = yAxis.startingExtremes,
newMaxY = yAxis.toValue(startPosY - mousePosY, true) + halfPointRangeY,
newMinY = yAxis.toValue(startPosY + chart.plotHeight - mousePosY, true) - halfPointRangeY;
if (xAxis.series.length && newMinX > Math.min(extremesX.dataMin, extremesX.min) && newMaxX < Math.max(extremesX.dataMax, extremesX.max) && newMinY > Math.min(extremesY.dataMin, extremesY.min) && newMaxY < Math.max(extremesY.dataMax, extremesY.max)) {
xAxis.setExtremes(newMinX, newMaxX, false, false, {
trigger: 'pan'
});
yAxis.setExtremes(newMinY, newMaxY, false, false, {
trigger: 'pan'
});
doRedraw = true;
}
chart.mouseDownX = mousePosX;
chart.mouseDownY = mousePosY;// set new reference for next run
if (doRedraw) {
chart.redraw(false);
}
});
}(Highcharts));
Starting extremes should be set in chart's callback or load event of a chart like:
}, function(chart){
chart.yAxis[0].startingExtremes = chart.yAxis[1].getExtremes();
});
Demo: http://jsfiddle.net/Lxjqed02/3/
Y-Axis panning isn't built into HighCharts. But, there is a plugin that does the trick: http://www.highcharts.com/plugin-registry/single/27/Y-Axis%20Panning
The examples show it working with highStock, but it works equally well with highCharts.

Resources