set Pie chart labels exact in center of Slices of PIE highcharts - javascript

i am using highcharts in one of my project. Highcharts JQuery version is being used and below is the reference:
http://code.highcharts.com/highcharts.js
Code used to draw chart is as below:
$(function () {
var chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type:'pie'
},
xAxis: {
categories: ['Jan', 'Feb', 'Mar', 'Apr']
},
plotOptions: {
series: {
dataLabels: {
enabled: true,
formatter: function() {
return Math.floor(this.percentage*100)/100 + ' %';
},
distance: 20,
connectorWidth : 0,
color: 'rgb(0, 127, 209)'
}
}
},
series: [{
data: [29.9, 71.5, 106.4, 129.2,29.9, 71.5, 106.4,
129.2,29.9, 71.5, 106.4, 129.2]
}]
});
});
The problem here i am facing that Slice labels are running here and there. I want all labels exact in center of each slice.
JS Fiddle link for demo is PIE Chart JSFiddle

Simplest, but not precise way would be to set negative distance for dataLabels. Value of distance would be related to size of chart, so it is possible to update series (with new distance for dataLabels) in load (to initiatie correct position) and redraw (after change of chart's size) events.
Precise solution for placing each of dataLabels in center of its slice can be based on getting center of slice and placing labels there. To keep chart responsive this adjustment of labels positions should be performed after each change of chart's size - in load and redraw events of chart.
Example: http://jsfiddle.net/mo8dfztx/2/
function redrawDatalabels() {
var chart = this,
cX = chart.series[0].center[0],
cY = chart.series[0].center[1],
shapeArgs, ang, posX, posY, bBox;
Highcharts.each(chart.series[0].data, function (point, i) {
if (point.dataLabel) {
bBox = point.dataLabel.getBBox();
shapeArgs = point.shapeArgs;
ang = (shapeArgs.end - shapeArgs.start) / 2 + shapeArgs.start;
posX = cX + (shapeArgs.r / 2) * Math.cos(ang);
posY = cY + (shapeArgs.r / 2) * Math.sin(ang);
point.dataLabel._pos.x = posX + ((point.labelPos[6] == "right" ? (1) : (-1)) * bBox.width/2);
point.dataLabel._pos.y = posY - bBox.height/2;
}
});
chart.series[0].placeDataLabels();
}
$(function () {
$('#container').highcharts({
chart: {
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false,
events: {
load: redrawDatalabels,
redraw: redrawDatalabels
}
},
title: {
text: 'Browser market shares at a specific website, 2014'
},
tooltip: {
pointFormat: '{series.name}: <b>{point.percentage:.1f}%</b>'
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: true,
connectorWidth: 0,
format: '<b>{point.name}</b>: {point.percentage:.1f} %',
style: {
color: (Highcharts.theme && Highcharts.theme.contrastTextColor) || 'black'
}
}
}
},
series: [{
type: 'pie',
name: 'Browser share',
data: [
['Firefox', 50],
['IE', 50],
['Safari', 25],
['Opera', 25]
]
}]
});
});

It looks like that there's no build-in feature to do this.
I think you have to use a negative distance, and if the chart size changes, you have to calculate the new distance to keep the labels centered on the slice.
You could handle this in the load event. Here's a simple example what you could refine to fit your needs:
http://jsfiddle.net/uhydP/317/
events: {
load: function(e) {
this.options.plotOptions.series.dataLabels.distance = (this.chartHeight / 5.5) * -1;
this.series[0].update(this.options);
}
}

Related

Highcharts: Change scale sizes

Let´s say you have an x-axis that goes [0, 3, 6, ...] and a y-axis that is like [0, 5, 10, ...].
Highcharts handles those values so that automatically, somehow a difference of 5 in y direction does not look bigger than a difference of 3 in x direction.
How can you change the distances between the values / make a 5 on the y axis appear as big as 5/3 of the change on the x axis? (so that p.e. a line from (0,0) to point (5,5) has a 45° angle)
Code example:
$.getJSON('https://cdn.jsdelivr.net/gh/highcharts/highcharts#v7.0.0/samples/data/usdeur.json', function (data) {
Highcharts.chart('container', {
chart: {
zoomType: 'x'
},
title: {
text: 'USD to EUR exchange rate over time'
},
subtitle: {
text: document.ontouchstart === undefined ? 'Click and drag in the plot area to zoom in' : 'Pinch the chart to zoom in'
},
xAxis: {
type: 'datetime'
},
yAxis: {
title: {
text: 'Exchange rate'
}
},
legend: {
enabled: false
},
plotOptions: {
area: {
fillColor: {
linearGradient: {
x1: 0,
y1: 0,
x2: 0,
y2: 1
},
stops: [
[0, Highcharts.getOptions().colors[0]],
[1, Highcharts.Color(Highcharts.getOptions().colors[0]).setOpacity(0).get('rgba')]
]
},
marker: {
radius: 2
},
lineWidth: 1,
states: {
hover: {
lineWidth: 1
}
},
threshold: null
}
},
series: [{
type: 'area',
name: 'USD to EUR',
data: data
}]
});
});
taken from demo
In the load event, you can calculate and adjust the height or width of the chart:
chart: {
events: {
load: function() {
var xAxis = this.xAxis[0],
yAxis = this.yAxis[0];
// Adjust xAxis
this.setSize(
yAxis.height / (yAxis.max - yAxis.min) *
(xAxis.max - xAxis.min) + this.plotLeft + this.chartWidth -
(this.plotLeft + this.plotWidth),
null,
false
);
}
}
},
Live demo: http://jsfiddle.net/BlackLabel/64Lxutce/
or if you do not want to change the size, you can adjust one of the axis extremes:
chart: {
events: {
load: function() {
var xAxis = this.xAxis[0],
yAxis = this.yAxis[0],
xAxisMax = xAxis.width /
(yAxis.height / (yAxis.max - yAxis.min)),
yAxisMax = yAxis.height /
(xAxis.width / (xAxis.max - xAxis.min));
if (xAxisMax < xAxis.max) {
this.update({
yAxis: {
max: yAxisMax - yAxis.min
}
}, true, true, false);
} else {
this.update({
xAxis: {
max: xAxisMax - xAxis.min
}
}, true, true, false);
}
}
}
},
Live demo: http://jsfiddle.net/BlackLabel/w3byrL28/
API Reference:
https://api.highcharts.com/highcharts/chart.events.load
https://api.highcharts.com/class-reference/Highcharts.Chart#update
https://api.highcharts.com/class-reference/Highcharts.Chart#setSize

Highcharts.js question: is it possible to keep some part of chart in visible area always, even if "overscoll" option is set

I need to show some empty space to far right of the chart. To do so I use "overscroll" option (https://api.highcharts.com/highstock/xAxis.overscroll). But if user zoom in chart and pans chart to far right there can be empty space without any part of candlestick chart displayed (https://screencast-o-matic.com/watch/cqnfFq3CII). Please advise is it possible to implement following chart behaviour and how to do so: to keep some part of chart in visible area always, even if "overscoll" option is set and user pans chart to the far right? Thanks!
Here is my code:
var ohlc = JSON.parse(ohlcStringified),
volume = JSON.parse(volumeStringified);
var interval = ohlc[ohlc.length - 1].x - ohlc[ohlc.length - 2].x;
var chart = Highcharts.stockChart('container', {
chart: {
borderWidth: 1,
panning: true,
},
title: {
text: 'Chart'
},
legend: {
enabled: true
},
rangeSelector: {
selected: 1,
enabled: false
},
scrollbar: {
enabled: false
},
xAxis: {
minPadding: 0.2,
overscroll: 50 * interval,
},
yAxis: [{
height: '40%'
}, {
top: '40%',
height: '30%',
offset: 0
}, {
top: '70%',
height: '30%',
offset: 0
}],
series: [{
type: 'candlestick',
id: 'candlestick',
name: 'AAPL',
data: ohlc,
tooltip: {
valueDecimals: 2
},
dataGrouping: {
enabled: false,
}
}, {
type: 'column',
id: 'volume',
name: 'Volume',
data: volume,
yAxis: 1,
dataGrouping: {
enabled: false,
}
}]
});
Here is live demo: http://jsfiddle.net/ogorobets/bfcs9gx7/2/
It's possible, however, it requires some custom logic. It can be achieved using xAxis.events.afterSetExtremes callback where you can check if the current axis minimum is greater than your limit (a value lower than maximum xData value). When it is true, set new axis extremes with your limit as a minimum value. Check the code and demo posted below.
Code:
xAxis: {
minPadding: 0.2,
overscroll: 50 * interval,
events: {
afterSetExtremes: function() {
var chart = this.chart,
xData = chart.series[0].xData,
maxValue = xData[xData.length - 5],
min = chart.xAxis[0].min,
max = chart.xAxis[0].max
if (min > maxValue) {
chart.xAxis[0].setExtremes(maxValue, max, true, false);
}
}
}
}
Demo:
https://jsfiddle.net/BlackLabel/p6d73nk8/
API reference:
https://api.highcharts.com/highcharts/xAxis.events.afterSetExtremes
https://api.highcharts.com/class-reference/Highcharts.Axis#setExtremes

JS Graphs using positive & negative values (Single line graph)

I want to integrate graph into my website with positive & negative values. If the value is negative then It will go into a red section, if no is positive then it will go into green section.
Right now I am unable to find such type of graph library in javascript, what will be the exact name of this type of graph?
Please let me know the solution.
You can create this type of chart by using Highcharts. Please check the example below:
Highcharts.chart('container', {
chart: {
inverted: true,
height: 80,
events: {
load: function() {
var yAxis = this.yAxis[0],
y = this.plotTop + this.plotHeight / 2,
center = yAxis.toPixels(0);
this.renderer.path([
'M', this.plotLeft, y, 'L', center, y
]).attr({
'stroke-width': 1,
stroke: 'red'
}).add();
this.renderer.path([
'M', center, y, 'L', this.plotSizeY + this.plotLeft, y
]).attr({
'stroke-width': 1,
stroke: 'green'
}).add();
}
}
},
title: {
text: ''
},
credits: {
enabled: false
},
legend: {
enabled: false
},
yAxis: {
title: {
text: ''
},
tickPositions: [-18, 0, 27],
gridLineWidth: 2
},
xAxis: {
visible: false
},
series: [{
type: 'scatter',
data: [21],
marker: {
fillColor: 'orange',
radius: 10
}
}]
});
Live demo: http://jsfiddle.net/BlackLabel/x9vo0tr6/
API: https://api.highcharts.com/highcharts
The closest name I've found is just a "number line", and it looks like this JavaScript library has a specific example of it:
https://jsxgraph.uni-bayreuth.de/wiki/index.php/Number_line
But I think in general you're better off building a custom one-dimensional plot of sorts, with D3.js, for example.

How do I remove padding from both sides of Highcharts area category chart?

There's too much padding on either side of the area chart and minPadding/maxPadding doesn't work with categories.
I want the area chart to start and end without any padding.
My code is below:
http://jsfiddle.net/nx4xeb4k/1/
$('#container').highcharts({
chart: {
type: 'area',
inverted: false
},
title: {
text: 'Too Much Padding On Either Side'
},
plotOptions: {
series: {
fillOpacity: 0.1
}
},
xAxis: {
type: 'category'
},
yAxis: {
title: {
text: 'Data Point'
}
},
legend: {
enabled: false
},
tooltip: {
pointFormat: '<b>{point.y}</b> points'
},
series: [{
name: 'Visits',
data: [
["Monday", 58],
["Tuesday", 65],
["Wednesday", 55],
["Thursday", 44],
["Friday", 56],
["Saturday", 65],
["Sunday", 69]
],
dataLabels: {
enabled: false,
rotation: -90,
color: '#FFFFFF',
align: 'right',
format: '{point.y:.1f}',
y: 10,
style: {
fontSize: '14px',
fontFamily: 'Verdana, sans-serif'
}
}
}]
});
A colleague of mine solved this very situation for some of my charts. Their solution was to remove the type: 'category' from the x-axis (making it a linear type instead) and instead replace the axis labels from an array.
Here's what's been changed:
First, I added an array of your x-axis labels.
var categoryLabels = ["Monday","Tuesday","Wednesday","Thursday","Friday",
"Saturday","Sunday"];
Next, I updated your series values to hold only the y-axis values.
series: [{
name: 'Visits',
data: [58, 65, 55, 44, 56, 65, 69],
Then, for your x-axis, I included a formatter function to pull in the labels from the array as substitutes for the default linear values.
xAxis: {
labels: {
formatter: function(){
return categoryLabels[this.value];
}
}
},
Lastly, I updated the tooltip options to show the values from the labels array.
tooltip: {
formatter: function () {
return categoryLabels[this.x] + ': ' + Highcharts.numberFormat(this.y,0);
}
},
I updated your fiddle with this tweaks: http://jsfiddle.net/brightmatrix/nx4xeb4k/4/
I hope you'll find this solution as useful as I have!
According to API, the default value of highcharts.xAxis.tickmarkPlacement is between and this is why the point of each category drops between two ticks on xAxis in your chart.
By setting highcharts.xAxis.tickmarkPlacement to on and playing around the value of highcharts.xAxis.min and highcharts.xAxis.max like this, you should be able to achieve what you want.
You can declare the min / max values to fix the problem.
var categoryLabels = ["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"];
//....
xAxis: {
min: 0.49,
max: categoryLabels.length - 1.49,
categories: categoryLabels,
type: 'category'
},
Example:
http://jsfiddle.net/fo04m7k7/

highcharts heatmap items opacity turns to 0

I m using Heat Map of Highcharts library in my app and i have begin to face a weird scenario. The map does not show some rows data, plz look at the following screen shot:
I see data in the column when I Inspect Element a cell. I noticed that all the row cell's opacity is set to 0. Changing it to 1 in chrome shows the item.
My JS code is as follows:
$highchart1.highcharts({
exporting: false,
credits: false,
chart: {
type: 'heatmap',
marginTop: 40,
marginBottom: 120
},
title: {
align: 'left',
text: 'Some chart title',
style: { color: 'red' }
},
xAxis: {
categories: pillarOrClusters,
labels: {
style: { color: '#000' }
}
},
yAxis: {
categories: locations,
title: summary.locationType,
labels: {
style: { color: '#000' }
}
},
colorAxis: {
min: 0,
minColor: '#FFFFFF',
maxColor: Highcharts.getOptions().colors[0]
},
legend: {
enabled: false
},
tooltip: {
formatter: function () {
return '<b>' + this.series.xAxis.categories[this.point.x] + '</b> has <br><b>' +
this.point.value + '</b> items in <br><b>' + this.series.yAxis.categories[this.point.y] + '</b>';
}
},
series: [{
name: 'Pillars per' + summary.locationType, // Loaded from Service
borderWidth: 1,
data: data,
dataLabels: {
enabled: true,
color: '#000000'
}
}]
});
Why would the map set opacity to 0 for entire row elements?
This issue was being raised only in Chrome and sometimes in IE because of insufficient height of the chart. I am calculating chart height as per items on yAxis as follows:
//locations is an array of strings to be shown on yAxis
var chartHieght = locations.length * 35;
if (chartHieght < 350) chartHieght = 350;
And then set it as follows:
chart: {
type: 'heatmap',
marginTop: 40,
height: chartHieght,
marginBottom: 130,
backgroundColor: '#F0F0F0',
borderColor: '#E5E5E5',
borderWidth: 2,
borderRadius: 4,
events: {
load: function () {
//THIS WAS A DIRTY WORKAROUND I WAS USING TO MAKE IT RENDER PROPERLY
/* $(".highcharts-data-labels g").attr("opacity", 1); */
}
}
}
Turning the height calculation as locations.length * 30 begins to render the same issue in Chrome. locations.length * 25 will cause the issue in IE as well.
Hope it helps someone.

Categories