How to draw arrows on a pie-chart with Highcharts? - highcharts

I am using a pie-chart of highchart and some settings are:-
pie: {
borderColor: '#000000',
innerSize: '60%'
},
series: [{
data: [
['projected Income', 44.2],
['Discount', 26.6],
['Annual Loss', 20]
]}]
}
Now my requirement is to show the arrow on the Annual loss graph as shown in picture of blue colour. Is it
possible to implement this in pie chart of Highcharts?
I have seen many
examples but those are explained for Line-Charts.

For line/scatter/bars you could use annotations but they are not available for pie/donut charts.
So using SVGRenderer you can add extra SVG elements to your pie/donut chart.
In my example below I draw a line using an SVG marker as arrow:
Highcharts.chart('container', {
chart: {
type: 'pie'
},
title: {
text: "My Title"
},
tooltip: {
pointFormat: '{series.name}: <b>{point.y:.1f}</b>'
},
plotOptions: {
pie: {
borderColor: '#000000',
innerSize: '60%',
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: false,
format: '<b>{point.name}</b>: {point.y:.1f}',
}
}
},
series: [{
data: [
['projected Income', 44.2],
['Discount', 26.6],
['Annual Loss', 20]
]
}]
}, function(chart) {
var point = chart.series[0].data[2];
var dx = chart.plotBox.x,
dy = chart.plotBox.y;
var radius = point.shapeArgs.r;
var angle = (point.shapeArgs.start + point.shapeArgs.end) / 2,
x = (radius * .9 * Math.cos(angle)) + point.shapeArgs.x,
y = (radius * .9 * Math.sin(angle)) + point.shapeArgs.y;
var x2 = (radius * 1.5 * Math.cos(angle)) + point.shapeArgs.x,
y2 = (radius * 1.5 * Math.sin(angle)) + point.shapeArgs.y;
var text = chart.renderer.text(
'Annual Loss',
x2 + dx, y2 + dy
).attr({
zIndex: 5
}).add(),
box = text.getBBox();
text.attr({
dx: -box.width / 2
});
chart.renderer.rect(box.x - 5 - box.width / 2, box.y - 5, box.width + 10, box.height + 10, 5).attr({
fill: '#FFFFEF',
'stroke': 'red',
'stroke-width': 1,
zIndex: 4
}).add();
console.log(point, chart);
chart.renderer.path({
'stroke': '#ff0000',
'stroke-width': 3,
'marker-end': "url(#markerArrow2)",
zIndex: 3,
'd': ['M', x2 + dx, y2 + dy, 'L', x + dx, y + dy]
}).add();
});
<script src="https://code.highcharts.com/highcharts.js"></script>
<div id="container" style="min-width: 310px; height: 400px; max-width: 600px; margin: 0 auto"></div>
<svg style="height: 0">
<defs>
<marker id="markerArrow" markerWidth="13" markerHeight="13" refX="2" refY="6"
orient="auto">
<path d="M2,2 L2,11 L10,6 L2,2 Z" style="fill: red;" />
</marker>
<marker id="markerArrow2" markerWidth="10" markerHeight="10" refX="6" refY="6"
orient="auto">
<path d="M2,2 L10,6 L2,10 L6,6 L2,2 Z" style="fill: red;" />
</marker>
</defs>
</svg>
Here is the link to a jsFiddle: https://jsfiddle.net/beaver71/k091v22e/

Related

Highcharts pie chart annotations are not centering

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'
}
}]

How can I find x and y coordinates of a point in a pie?

How can I get the X and Y coordinates of a point?
I would like to place a badge at the arc line, right between the two points in the pie chart. At the moment I add circle and text using the chart renderer.
$(function() {
$('#chart').highcharts({
chart: {
type: 'pie',
options3d: {
enabled: false,
alpha: 0
},
height: 470
},
colors: ['#EF3F3E', '#757575'],
title: {
style: {
fontSize: '90px',
align: 'center',
color: '#EF3F3E'
},
verticalAlign: 'middle'
},
tooltip: {
enabled: false
},
plotOptions: {
pie: {
innerSize: 420,
dataLabels: {
enabled: false
},
shadow: false,
center: ['50%', '50%'],
borderWidth: 0
}
},
series: [{
name: 'Delivered amount',
data: [56, 44]
}]
}, function(chart) { // on complete
chart.setTitle({
color: "#333333",
});
chart.renderer.circle(650, 420, 50).attr({
fill: '#3A3A3B',
'stroke-width': 0,
zIndex: 3
}).add();
chart.renderer.circle(650, 420, 40).attr({
fill: '#EF3F3E',
'stroke-width': 0,
zIndex: 4
}).add();
chart.customText = chart.renderer.text('30', 635, 430)
.css({
color: 'black',
font: '28px Arial, sans-serif',
'z-index': '5'
}).attr({
zIndex: 5
}).add();
});
});
https://jsfiddle.net/yq2s5ng1/5/
Is there a better way to display this badge? For example using markers insted of rendering custom elements?
EDIT:
In case anyone is interested, here is how I solved this:
function getCoordinates() {
var x;
var y;
var h = chart.series[0].data[0].shapeArgs.x;
var k = chart.series[0].data[0].shapeArgs.y;
var r = chart.series[0].data[0].shapeArgs.innerR;
//var theta = chart.series[0].data[0].angle;
//var theta = chart.series[0].data[0].series.endAngleRad;
var theta = chart.series[0].data[0].shapeArgs.end;
x = h + r * Math.cos(theta);
y = k + r * Math.sin(theta);
return { x: x, y: y };
}
This post helped me to find the Cartesian coordinates: https://math.stackexchange.com/questions/475917/how-to-find-position-of-a-point-based-on-known-angle-radius-and-center-of-rotat

Highcharts Solid Gauge (Thermometer) ... Color from -30 to +60

how I can the yAxis Stops values adjust so that the shows me different colors depending on the temperature value?
The best would be as follows:
-30 to 0 = blue
0 to 12 = light blue
12 to 25 = green
25 to 30 = orange
30 to 60 = red
Here my Code:
$(function () {
var gaugeOptions = {
chart: {type: 'solidgauge'},
title: null,
pane: {
size: '90%',
startAngle: -180,
endAngle: 90,
background: {
backgroundColor: '#EEE',
innerRadius: '95%',
outerRadius: '100%',
shape: 'arc'
}
},
tooltip: {enabled: false},
// the value axis
yAxis: {
stops: [
[0.1, '#00f'],
[0.2, '#0f0'],
[0.3, '#f00']
],
lineWidth: 0,
minorTickInterval: 0,
tickPixelInterval: 50,
tickWidth: 1,
labels: {
enabled: true,
distance: 10
}
},
plotOptions: {
solidgauge: {
innerRadius: '95%',
dataLabels: {
y: 5,
borderWidth: 0,
useHTML: true
}
}
}
};
$('#temp001').highcharts(Highcharts.merge(gaugeOptions, {
yAxis: {
min: -30,
max: 60
},
credits: {
enabled: false
},
series: [{
name: 'inTemp',
data: [-15.5], /////// Temp Value //////////
dataLabels: {
format: '<div style="text-align:center"><span style="font-size:25px;color:' +((Highcharts.theme && Highcharts.theme.contrastTextColor) || 'black') + '">{y} °C</span><br/>' + '<span style="font-size:12px;color:silver">abcde</span></div>'
}
}]
}));
});
Sorry for my Bad English....German ist better
Here you can find API about yAxis.stops:
http://api.highcharts.com/highcharts#yAxis.stops
The values in stops are between 0 and 1, where 0 is the min value of your axis and 1 is the max value. The values between 0 and 1 are proportional to values of axis.
If you are having axis with min value of -30 and max value of 60 and you want to have stop from 30, the value for stop will be
60/(60-(-30))
You should set your colors in RGB format of "#XXYYZZ" if you want to have smooth transition between colors of your stops.
stops: [
[0, '#000088'],
[29 / 90, '#000088'],
[30 / 90, '#5555ff'],
[41 / 90, '#5555ff'],
[42 / 90, '#00ff00'],
[54 / 90, '#00ff00'],
[55 / 90, '#ff8c00'],
[59 / 90, '#ff8c00'],
[60 / 90, '#ff0000']
],
example:
http://jsfiddle.net/izothep/o35xLwbk/6/

datatable inside Highcharts-Pie chart

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.

How to draw disconnected straight lines over a graph?

I'm trying to plot some straight lines over my chart and have gotten most of the way there, but am now stuck with the offsets. The red lines below are supposed to draw a line between two markers, but as you can see, they're high and left.
I was expecting plotX and plotY to sort this out for me, but I'm missing something. There are four series in the chart: the green, the blue, the red triangles, and the red triangle-downs. I want to draw a line linking the red triangles (3rd series) and the red triangle-downs (4th series). I'm currently doing it by a callback which loops over series three and adds a path using plotX and plotY.
It currently looks something like this, but I'm open to better ways.
function(){
var chart = this;
$.each(chart.series[2].data, function(index, value){
startX = chart.series[2].data[index].plotX;
startY = chart.series[2].data[index].plotY;
endX = chart.series[3].data[index].plotX
endY = chart.series[3].data[index].plotY
chart.renderer.path(['M', startX, startY, 'L', endX, endY])
.attr({ 'stroke-width': 2, stroke: 'red' })
.add();
console.log(index, startX, startY, endX, endY);
})
});
The axis and everything else look something like:
$(document).ready(function () {
chart1 = new Highcharts.StockChart({
chart:{
renderTo:'container'
},
yAxis:[
{ // Leader yAxis
labels:{
formatter:function () { return "$" + this.value.toFixed(2); },
style:{ color:'green' }
},
title:{
text:'Leader',
style:{ color:'green' }
}
},
{ // Follower yAxis
title:{
text:'Follower',
style:{ color:'#4572A7' }
},
labels:{
formatter: function () { return "$" + this.value.toFixed(2); },
style: { color:'#4572A7' }
},
opposite: true
}],
series:[
{
type: 'line',
name: 'Buyer Moving Average',
data: buyer,
color: 'green',
yAxis: 1
},{
type:'line',
name:'Data',
data: equity,
color: "#4572A7",
yAxis: 0
},{
type: 'scatter',
name: 'Buys',
data: buys,
color: 'red',
marker: { symbol: "triangle" },
yAxis: 0
},{
type:'scatter',
name:'Sells',
data: [{{ sells }}],
color: 'red',
marker: { symbol: "triangle-down" },
yAxis: 0
}
]
Funny how being forced to turn a problem into a question helps me straighten out my thoughts and frustrations enough to find an answer for myself...
The plotX and plotY attributes don't take into account the labelling and whatever else that the axes introduce, so it's just a matter of finding the offset they create and adding it in:
function(){
var chart = this;
xoffset = chart.series[2].xAxis.left;
yoffset = chart.series[2].xAxis.top;
$.each(chart.series[2].data, function(index, value){
startX = chart.series[2].data[index].plotX + xoffset;
startY = chart.series[2].data[index].plotY + yoffset;
endX = chart.series[3].data[index].plotX + xoffset;
endY = chart.series[3].data[index].plotY + yoffset;
chart.renderer.path(['M', startX, startY, 'L', endX, endY])
.attr({ 'stroke-width': 2, stroke: 'red' })
.add();
console.log(index, chart.series[2].xAxis.left, startX, startY, endX, endY);
}

Resources