I have 2 pie charts rendered next to each other corresponding 2 series. I want to add a title under each series, but don't want to use the title property, because each Highcharts component only gets one title. I've opted to use annotations and that is working, which requires me to manually specify the x and y coordinates for the annotation labels. I'm using a formula to calculate these exact positions. However, when I render the annotations, they don't seem to exactly line up in the middle of each chart.
My chart options look like this:
const width = 700
const height = 200
Highcharts.chart('container', {
chart: {
type: 'pie',
width,
height
},
plotOptions: {
pie: {
dataLabels: {
enabled: false
}
}
},
annotations: [{
labels: [{
point: {
x: 0.33 * width,
y: height
},
text: "centered"
}]
}, {
labels: [{
point: {
x: 0.635 * width,
y: height
},
text: "also centered"
}]
}],
series: [
{
center: ['33%', '50%'],
type: 'pie',
data: [
['Firefox', 44.2],
['IE7', 26.6],
['IE6', 20],
['Chrome', 3.1],
['Other', 5.4]
]
},
{
center: ['66%', '50%'],
type: 'pie',
data: [
['Firefox', 44.2],
['IE7', 26.6],
['IE6', 20],
['Chrome', 3.1],
['Other', 5.4]
]
}]
});
Here's what it looks like now: https://jsfiddle.net/0cfztdms/
And here's what I want to achieve without hardcoding the x positions:
Pie charts with centered annotations
I think that a better solution will be rendering the custom label via using SVGRendere tool than using the annotation feature.
Demo: https://jsfiddle.net/BlackLabel/L08bvngk/
render() {
let chart = this;
chart.series.forEach((s, i) => {
if (chart['label' + i]) {
chart['label' + i].destroy();
}
chart['label' + i] = chart.renderer.label('testtestestest', 0, 0)
.css({
color: '#FFFFFF'
})
.attr({
fill: 'rgba(0, 0, 0, 0.75)',
padding: 8,
r: 5,
zIndex: 6
})
.add();
//center the label
chart['label' + i].translate(s.center[0] + chart.plotLeft - chart['label' + i].getBBox().width / 2, chart.plotHeight)
})
}
API: https://api.highcharts.com/class-reference/Highcharts.SVGRenderer#label
API: https://api.highcharts.com/highcharts/chart.events.render
I figured out a way to center my labels without having to do the manual calculations using Highcharts annotations module. Set anchorX = 'center' and anchorY = 'middle' (these props are from the annotations module) will automatically center the annotations for you. Read more here
const width = 600;
annotations: [{
labels: [{
point: {
x: (1 / numberOfCharts + 1) * width,
y: 200,
anchorX: 'center',
anchorY: 'middle'
},
text: 'Label 1'
}, {
point: {
x: (1 / numberOfCharts + 1) * 2 * width,
y: 200,
anchorX: 'center',
anchorY: 'middle'
},
text: 'Label 2'
}
}]
Related
Example Chart Image
I want to show tooltip for Approval Count as 0 on hovering anywhere in it's general vicinity, is that possible with highcharts?
You can render this particular column as a dummy point - full range & transparent color to show a tooltip for it.
Highcharts.chart('container', {
chart: {
type: 'bar'
},
yAxis: {
max: 10
},
tooltip: {
formatter(tooltip) {
if (this.point.isEmpty) {
return 'Null';
}
return tooltip.defaultFormatter.call(this, tooltip);
}
},
series: [{
data: [{
x: 0,
y: 2
}, {
x: 1,
y: 3
}, {
x: 2,
y: 10,
color: 'transparent',
isEmpty: true
}, {
x: 3,
y: 8
}, {
x: 4,
y: 2
}]
}]
});
Demo: https://jsfiddle.net/BlackLabel/ef8sj4no/
API: https://api.highcharts.com/highcharts/tooltip.formatter
I am trying to achieve combined 2 Semidonut Pie Charts series to show Current year and Last year percentage with my data .
At the same time I am trying to overlay another series with data which will represent the YOY percentage increase or decrease which will appear as label outside my outer pie as "+50%" , "-60%"
Since YOY can be negative and this disturb's the Pie . I was reading that Pie is not ideal to put the negative numbers but visually in my usecase customer feels this will be great .
I tried to massage the YOY data with negative to multiply with (-1) and put into pie and I kind of able to represent the number outside pie but can't bring the "+" or "-" with "%" as valuesuffix .
I have working example here but again this is with 2 data series ... my 3rd series will be "YOY%" with the datalabel display outside which is not added here as 3rd series with negative bring a weird donut .
Anybody has idea how to implement this solution to represent series 3 with YOY Outside as regular datalabels ?
https://codepen.io/pauldx/pen/BayyJaa
Highcharts.chart('container', {
chart: {
plotBackgroundColor: null,
plotBorderWidth: 0,
plotShadow: false
},
title: {
text: 'Browser<br>shares<br>2017',
align: 'center',
verticalAlign: 'middle',
y: 60
},
tooltip: {
pointFormat: '{series.name}: <b>{point.percentage:.1f}%</b>'
},
plotOptions: {
pie: {
dataLabels: {
enabled: true,
distance: -50,
style: {
fontWeight: 'bold',
color: 'white'
}
},
startAngle: -90,
endAngle: 90,
center: ['50%', '75%'],
size: '110%'
}
},
series: [{
type: 'pie',
innerSize: '50%',
dataLabels: {
enabled: true,
// inside: true,
distance: -70,
},
data: [
['LYA', 58.9],
['LYB', 28.9],
['LYC', 30.29],
]
},
{
type: 'pie',
name: 'Browser share',
innerSize: '70%',
dataLabels: {
enabled: true,
// inside: true,
distance: -20,
},
data: [
['CYA', 20],
['CYB', 18.9],
['CYC', 70.29],
]
}]
});
As I understood - you would like to add only the dataLabels with calculated YOY value, am I right? Or do you want to add a whole series? If just a dataLabels - there is a guideline how to achieve it by adding custom dataLabels:
events: {
render() {
let chart = this,
yoyValue,
x,
y;
chart.series[1].points.forEach((p, i) => {
if (chart['label' + i]) {
chart['label' + i].destroy();
}
yoyValue = Math.floor(((p.y - chart.series[0].points[i].y) / p.y) * 100);
x = p.dataLabel.translateX - (p.shapeArgs.end == 0 ? -40 : 30);
y = p.dataLabel.translateY;
chart['label' + i] = chart.renderer.text(yoyValue + '%', x, y).attr({
zIndex: 100,
}).css({
fontWeight: 'bold',
color: 'white',
textOutline: '1px contrast'
}).add();
})
}
}
Demo: https://jsfiddle.net/BlackLabel/p82L4ad1/1/
API: https://api.highcharts.com/highcharts/chart.events.render
API: https://api.highcharts.com/class-reference/Highcharts.SVGRenderer#text
I'm trying to create a Spider graph that has the y-axes labels offset with extended gridlines.
Is this possible to achieve with just one graph, or do I have to create two separate graphs and overlay them? I've tried ticklines, gridlines, and they all get stuck in the polar coordinates.
Here's my attempt at trying to accomplish this:
http://jsfiddle.net/6d6jrfhs/3/
{
chart: {
polar: true,
type: 'line'
},
title: {
text: "# of Impacts",
x: -80
},
pane: {
size: '80%',
startAngle: 0,
},
xAxis: {
categories: ['Back', 'Left', 'Front', 'Top',
'Right'],
tickmarkPlacement: 'on',
lineWidth: 0
},
yAxis: {
gridLineInterpolation: 'polygon',
lineWidth: 0,
min: 0,
offset: 0,
labels: {
align: 'left',
x: -100,
y: 0
},
tickLength: 500,
plotLines: [{
color: 'red', // Color value
dashStyle: 'longdashdot', // Style of the plot line. Default to solid
value: 40000, // Value of where the line will appear
width: 1 // Width of the line
}]
},
legend: {
align: 'right',
verticalAlign: 'top',
y: 70,
layout: 'vertical'
},
series: [{
type:'area',
name: 'Low Impact',
data: [43000, 19000, 60000, 35000, 17000],
pointPlacement: 'off'
}, {
type:'area',
name: 'Actual Spending',
data: [50000, 39000, 42000, 31000, 26000],
pointPlacement: 'off'
}]
}
This demo shows how to find labels (SVG elements) in the chart object and create additional gridline using SVG Renderer: http://jsfiddle.net/kkulig/eg7p3r48/
events: {
render: function() {
var yAxis = this.yAxis[0],
renderer = this.renderer,
label = yAxis.ticks[0].label;
renderer.path(['M', label.xy.x, label.xy.y, 'l', label.xy.x - xOffset - 30, 0]).attr({
stroke: 'black',
'stroke-width': 1
}).add();
}
}
API reference: https://api.highcharts.com/class-reference/Highcharts.SVGRenderer#path
I've been messing around with the demo code for highcharts pie charts to see if I can accomplish several things...
Have labels inside unless the slice is too thin. If it's too thin,
label should be outside
Color fonts white. If the slice is outside or if the slice is a
specific color, this should be black
In the below, I was able to address some of what I'm trying to do in the bottom function. It moves labels outside based on the percentage of the slice and also colors it black. But...
I don't want to use attr({y:x}) for adjusting the position when the
slice is too thin. I would rather be able to use distance.
I'm not sure how to check the color of a slice to then be able to color the font. Ideally it would be something like the function
below that uses "point" but would be for the slice instead.
Anyone know how to handle?
$(function () {
Highcharts.chart('container', {
chart: {
type: 'pie'
},
plotOptions: {
pie: {
dataLabels: {
useHTML: true,
enabled: true,
format: '{point.percentage:.1f} %',
color: 'white',
distance: -40
},
showInLegend: true,
}
},
series: [{
data: [
['Firefox', 45.0],
['Chrome', 26.8],
['IE 11', 12.8],
['Edge', 8.5],
['Opera', 6.2],
['Other', 0.7],
]
}]
},
function(chartObj) {
$.each(chartObj.series[0].data, function(i, point) {
if(point.percentage < 6) {
point.dataLabel.css({color: 'black'}),
point.dataLabel.attr({y: -20})
}
})
});
});
</script>
Solution to your problem is to take angle of desired arc (pie slice) and calculate x and y using Math.cos and Math.sin functions.
const options = {
chart: {
type: 'pie',
events: {
load: function() {
const series = this.series[0];
const points = series.data;
const chart = this;
points.forEach(function(point) {
if (point.y <= 1) {
const myOffset = 40;
const {x: centerX, y: centerY} = point.graphic.attr();
const {x, y} = point.dataLabel.attr();
const angle = point.angle;
point.dataLabel.attr({
x: x + Math.cos(angle) * myOffset,
y: y + Math.sin(angle) * myOffset
});
point.dataLabel.css({color: 'black'});
}
});
}
}
},
title: {
text: ''
},
plotOptions: {
pie: {
dataLabels: {
enabled: true,
distance: -25,
formatter: function() {
return this.y + '%';
}
}
}
},
series: [{
innerSize: '60%',
data: [40, 20, 20, 19, 1]
}]
}
const chart = Highcharts.chart('container', options);
Live example:
https://jsfiddle.net/b1ya1x9h/
I want to display the datatable inside Pie chart using Highcharts.I can display the table outside but on exporting the image, datatable is not exported.
So my aim is to display datatable inside the Pie chart.
Refering to this.I was able to partly acheive it.demo
But how can i give the column headers and borders to it?
$(function () {
Highcharts.drawTable = function() {
// user options
var tableTop = 200,
colWidth = 60,
tableLeft = 50,
rowHeight = 20,
cellPadding = 2.5,
valueDecimals = 1,
valueSuffix = '';
// internal variables
var chart = this,
series = chart.series,
renderer = chart.renderer,
cellLeft = tableLeft;
// draw category labels
$.each(series, function(serie_index, serie) {
renderer.text(
serie.name,
cellLeft + cellPadding,
tableTop + (serie_index + 1) * rowHeight - cellPadding
)
.css({
fontWeight: 'bold'
})
.add();
});
$.each(series[0].data, function(i) {
renderer.text(
series[0].data[i].name,
cellLeft + colWidth - cellPadding,
tableTop + (i + 2) * rowHeight - cellPadding
)
.attr({
align: 'right'
})
.add();
});
$.each(series[0].data, function(i) {
renderer.text(
Highcharts.numberFormat(series[0].data[i].y, valueDecimals) + valueSuffix,
150,
tableTop + (i + 2) * rowHeight - cellPadding
)
.attr({
align: 'left'
})
.add();
});
}
$('#container').highcharts({
chart: {
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false,
events: {
load: Highcharts.drawTable
},
height: 600,
width: 800,
marginBottom: 250
},
title: {
text: 'Browser market shares at a specific website, 2010'
},
tooltip: {
pointFormat: '{series.name}: <b>{point.percentage:.1f}%</b>'
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: true,
color: '#000000',
connectorColor: '#000000',
format: '<b>{point.name}</b>: {point.percentage:.1f} %'
}
}
},
series: [{
type: 'pie',
name: 'Browser share',
data: [
['Firefox', 45.0],
['IE', 26.8],
{
name: 'Chrome',
y: 12.8,
sliced: true,
selected: true
},
['Safari', 8.5],
['Opera', 6.2],
['Others', 0.7]
]
}]
});
});
For the column headers, I don't know. Depends on what you want to do.
As for the borders, since that's SVG, you could draw the borders using RECT and PATH. Take a look at this fork of your demo for some crude borders and maybe you can improve on it.