How to create equal width solidgauge for any number of series? - javascript

I am facing some problem to create solidgauge chart using HighCharts library.
I want to make width of every series equal and also their background but unable to understand innerRadius, outerRadius, radius of data and pane background correctly.
It should be flexible with any container width.
jsfiddle here
JS:
function buildChartOptions(series)
{
var nextRadius = 50, dataRadiusDiff = 25, nextBgInnerRadius = 38, bgRadiusDiff = 24;
this.options = {
chart: {},
title: {},
tooltip: {},
pane: {},
yAxis: {},
plotOptions: {},
series: {},
};
this.options.chart = {
type: 'solidgauge',
marginTop: 50
};
this.options.title = {
text: null,
style: {
fontSize: '24px',
}
};
this.options.tooltip = {
borderWidth: 0,
backgroundColor: 'none',
shadow: false,
style: {
fontSize: '12px'
},
pointFormat: '{series.name}<br><span style="padding:10px;font-size:2em; color: {point.color}; font-weight: bold">{point.y} %</span>',
positioner: function (labelWidth, labelHeight) {
return {
x: 200 - labelWidth / 2,
y: 180
};
}
};
var chartWidth = (100-(series.length * 8 )),
borderWidth = (100 - 11.02 * series.length);
chartWidth = chartWidth < 30 ? 35 : chartWidth;
borderWidth = borderWidth < 10 ? 15: borderWidth;
borderWidth = 34;
console.log('chart ', chartWidth, 'border ', borderWidth);
this.options.pane = {
startAngle: -90,
endAngle: 90,
size: Math.abs(chartWidth) + '%',
background: []
};
this.options.yAxis = {};
this.options.plotOptions = {
solidgauge: {
borderWidth: borderWidth + 'px',
dataLabels: {
enabled: false
},
linecap: 'square',
stickyTracking: true
}
};
this.options.series = [];
for(var i=0; i<series.length; i++)
{
this.options.series.push({
name: series[i].name,
borderColor: Highcharts.getOptions().colors[i],
data:[{
color: Highcharts.getOptions().colors[i],
radius: nextRadius+'%',
innerRadius: nextRadius+'%',
y: (i*10)+20
}]
});
nextRadius += dataRadiusDiff;
this.options.pane.background.push({
outerRadius: parseInt(nextBgInnerRadius + bgRadiusDiff) + '%',
innerRadius: nextBgInnerRadius+'%',
backgroundColor: Highcharts.Color(Highcharts.getOptions().colors[i]).setOpacity(0.5).get(),
borderWidth: 1,
shape: 'arc'
});
nextBgInnerRadius += (bgRadiusDiff + 1);
}
this.options.series.reverse();
this.options.pane.background.reverse();
var chart = Highcharts.chart('container', this.options);
return this.options;
}
var series = [
{name:'A',id :0, data:10, color:'#043310', bgcolor:'#033249'},
{name:'B',id :1, data:30, color:'#024230', bgcolor:'#134349'},
{name:'C',id :2, data:50, color:'#042210', bgcolor:'#022249'},
{name:'D',id :2, data:150, color:'#042210', bgcolor:'#022249'},
{name:'E',id :2, data:250, color:'#042210', bgcolor:'#022249'},
];/*
{name:'F',id :2, data:350, color:'#042210', bgcolor:'#022249'},
{name:'G',id :2, data:150, color:'#042210', bgcolor:'#022249'},
{name:'H',id :2, data:240, color:'#042210', bgcolor:'#022249'},
{name:'I',id :1, data:30, color:'#024230', bgcolor:'#134349'},
{name:'J',id :2, data:50, color:'#042210', bgcolor:'#022249'},
{name:'I',id :1, data:30, color:'#024230', bgcolor:'#134349'},
{name:'J',id :2, data:50, color:'#042210', bgcolor:'#022249'},
];*/
buildChartOptions(series);
Can some one help me with it ?

You do not require an extra calculation for a different container's width to apply equal innerRadius, outerRadius of all panes and radius, innerRadius of all series. If you want series and panes display with the same width and you want to set it dynamically, you can write a simple function and set min, max radius and caluculate radiusStep. For the reference, take a look at the example I posted below.
API Reference:
http://api.highcharts.com/highcharts/series%3Csolidgauge%3E.data.radius
http://api.highcharts.com/highcharts/series%3Csolidgauge%3E.data.innerRadius
Example:
http://jsfiddle.net/wt5Lp09r/

Related

I want to make some custom variablepie chart for some special requirement

I got stuck somewhere and there I want your help. I want a Pie chart data-label feature into the variable Pie chart. which is like the data should stay in the centre of the chart piece.
I tried so many ways but not fit in the centre like the data label indication line.
Please check the code and design below and help me to fix my issue...
This's the design reference for the Output
This's the current output of my code
This's the link for the current output...
<script>
Highcharts.setOptions({
colors: ['#2B2E33', '#4D5566', '#8590A6', '#B8C3D9', '#02D42E']
});
Highcharts.chart('container', {
chart: {
type: 'variablepie',
style: {
fontFamily: "'Montserrat-Regular', 'sans-serif'",
letterSpacing: '0.5px',
},
events: {
load: function() {
var series = this.series[0],
distance = series.points[0].shapeArgs.r / 2;
series.update({
dataLabels: {
distance: -distance
}
});
}
}
},
title: {
text: ' '
},
tooltip: {
headerFormat: '',
pointFormat: '<span style="color:{point.color}">\u25CF</span> <b> {point.name}</b> {point.y}<br/>'
},
accessibility: {
point: {
valueSuffix: '%'
}
},
legend: {
symbolRadius: 0,
itemStyle: {
fontWeight: 'bold',
color:'#8590A6',
textOverflow: 'clip'
}
},
plotOptions: {
variablepie: {
allowPointSelect: true,
cursor: 'pointer',
//showInLegend: true,
dataLabels: {
enabled: true,
alignTo: 'center',
format: '{point.percentage:.1f} %',
distance: -10,
style:{
textOutline: 'none',
fontSize: 15,
lineHeight: 0,
color:'white',
fontWeight: 'bold',
},
filter: {
property: 'percentage',
operator: '>',
value: 2
}
}
}
},
series: [{
innerSize: '40%',
zMin: 0,
name: 'countries',
data: [{
name: 'Google',
y: 25,
z: 100,
}, {
name: 'Facebook',
y: 14,
z: 115
}, {
name: 'Pinterest',
y: 11,
z: 85
}, {
name: 'Yelp',
y: 10,
z: 90
}, {
name: 'Local Services',
y: 40,
z: 140
}]
}]
}, function (chart) {
$legend = $('#customLegend');
$.each(chart.series[0].data, function (j, data) {
$legend.append('<div class="item"><div class="symbol" style="background-color:'+data.color+'"></div><div class="serieName" id="">' + data.name + '</div><div class="value" id="">' + data.y + '</div></div>');
});
$('#customLegend .item').click(function(){
var inx = $(this).index(),
point = chart.series[0].data[inx];
if(point.visible)
point.setVisible(false);
else
point.setVisible(true);
});
});
You can add some extra info to your serie in order to position you label correctly.
For instance:
{
name: 'Pinterest',
y: 11,
z: 85,
dataLabels: {
distance: -30,
x: -20
}
}, {
name: 'Yelp',
y: 10,
z: 90,
dataLabels: {
distance: -30,
x: 30
}
This may help for static charts.
I prepared a demo where the center of the arc point is calculated and used as translate function coordinates to center the data label.
events: {
render: function() {
const series = this.series[0];
series.points.forEach(p => {
const dataLabel = p.dataLabel;
const args = p.shapeArgs;
const angle = (args.start + args.end) / 2;
const r = (args.innerR + args.r) / 2;
const x = args.x + (r * Math.cos(angle)) - dataLabel.bBox.width / 2;
const y = args.y + (r * Math.sin(angle)) - dataLabel.bBox.height / 2;
dataLabel.translate(x, y)
})
}
}
Demo: https://jsfiddle.net/BlackLabel/c3wf85g7/

createRadialGradient with a circle centered on the bottom left of the bubble chart

I created a bubble chart with chart.JS 2.0 (risk matrix). I would now like to color the background with a green circle centered on the bottom left of the chart which would become red when expanding to the top right.
I managed to create the circle on the background which generates the following chart :
I would now like to have the circle centered on the bottom left but I am struggling to deal with the coordinates.
Chart.pluginService.register({
beforeDraw: function(chart, easing) {
if (chart.config.options.chartArea && chart.config.options.chartArea.backgroundColor) {
var helpers = Chart.helpers;
var ctx = chart.chart.ctx;
var chartArea = chart.chartArea;
// {left: 45.073828125, top: 34.4, right: 588, bottom: 538.2}
ctx.save();
var canevas = document.querySelector("canvas");
var contexte = canevas.getContext('2d');
X = chartArea.right;
Y = chartArea.bottom;
leftoffset = chartArea.left;
topoffset = chartArea.top;
// var gradient = ctx.createLinearGradient(0, 70, 70, 0);
var gradient = ctx.createRadialGradient(X / 1.34, Y / 1.412, X / 8, X / 4 * 3, Y / 2, X / 3);
gradient.addColorStop(0, "green");
gradient.addColorStop(0.5, "orange");
gradient.addColorStop(1, "red");
ctx.fillStyle = gradient;
ctx.fillRect(chartArea.left, chartArea.top, chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
}
}
});
var myBubbleChart = new Chart(document.getElementById("bubble-chart"), {
type: 'bubble',
data: {
labels: "Africa",
datasets: [{
idu: 29,
label: ["Hurricane"],
backgroundColor: "#398B93",
data: [{
x: 4,
y: 1,
r: 15
}]
},
{
idu: 30,
label: ["Flooding"],
backgroundColor: "#398B93",
data: [{
x: 5,
y: 4,
r: 15
}]
},
{
idu: 31,
label: ["Cyber-attack"],
backgroundColor: "#398B93",
data: [{
x: 1,
y: 4,
r: 15
}]
},
]
},
options: {
chartArea: {
backgroundColor: 'linear-gradient(0.25turn, #3f87a6, #ebf8e1, #f69d3c)'
},
title: {
display: true,
text: 'Risk matrix'
},
scales: {
yAxes: [{
scaleLabel: {
display: true,
labelString: "Likelihood"
},
ticks: {
min: 0, // Controls where axis starts
max: 6, // Controls where axis finishes
stepSize: 1,
display: true,
callback: function(tick) {
return (tick !== 0) && (tick !== 6) ? tick : '';
}
},
gridLines: {
display: true,
drawBorder: false,
lineWidth: 1, // Width of line,
offsetGridLines: true,
color: '#EBEEEE',
}
}],
xAxes: [{
scaleLabel: {
display: true,
labelString: "Impact"
},
ticks: {
min: 0, // Controls where axis starts
max: 6, // Controls where axis finishes
stepSize: 1,
display: true,
callback: function(tick) {
return (tick !== 0) && (tick !== 6) ? tick : '';
}
},
gridLines: {
display: true,
drawBorder: false,
offsetGridLines: true,
color: '#ebeeee',
}
}]
},
legend: {
display: false,
labels: {
fontColor: 'rgb(255, 99, 132)'
}
},
jitter: true,
}
});
#bubble-chart {
max-width: 90%;
max-height: 90%;
}
<canvas id="bubble-chart" width="800" height="800"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0"></script>
Thanks a lot

Marker is not aligning in Gauge chart using hight chart

I am trying to implement a gauge chart using high chart from data -100 to +100, when I tried to set initial data > 50 means custom marker aligning on the gauge. But if data is < 50 (Ex: 20 ) means custom marker is not aligning on the gauge line. JSFiddleLink
I tried in many way but unable to acheive.
Highcharts.chart('container', {
chart: {
style: {
fontFamily: "FuturaPTCond",
fontSize: "16px"
},
type: "solidgauge",
events: {
load: function() {
var elementSVG;
var chart = this,
counter = 0,
drawCircle = setInterval(function() {
if (++counter >= 1000) {
clearInterval(drawCircle);
}
renderCircle(chart);
function renderCircle(chart) {
let chartData = chart.userOptions.series[0].data[0];
let color =
chartData < -21
? "#DC143C"
: chartData > -21 && chartData < 21
? "#FF4500"
: chartData > 21 && chartData < 51
? "#FFFF00"
: chartData > 51 && chartData < 71
? "#00BFFF"
: chartData > 71 && chartData < 91
? "#ADFF2F"
: "#FF1493";
var series = chart.series[0],
pathDivided = series.points[0].graphic.attr("d").split(" "),
pathElemArr = [];
pathDivided.forEach(function(el, inx) {
if (el === "L") {
pathElemArr.push(parseFloat(pathDivided[inx + 1]));
pathElemArr.push(parseFloat(pathDivided[inx + 2]));
}
});
if (elementSVG) {
elementSVG.destroy();
}
document.getElementById(
"BackgroundColor"
).style.backgroundColor = "#fff";
elementSVG = chart.renderer
.circle(pathElemArr[0] + 11.25, pathElemArr[1], 10)
.attr({
fill: "#fff",
stroke: color,
width: "30px",
"stroke-width": 8,
zIndex: 10,
startAngle: -90,
endAngle: 90
})
.add();
}
}, 1);
$(".highcharts-axis-title").attr("x", 600.5);
$(".highcharts-axis-title").attr("y", 395.25);
$(".highcharts-credits").attr("x", 725);
},
redraw: function() {
$(".highcharts-axis-title").attr("x", 600.5);
$(".highcharts-axis-title").attr("y", 395.25);
$(".highcharts-credits").attr("x", 725);
}
}
},
title: null,
pane: {
center: ["50%", "85%"],
size: "98%",
startAngle: -90,
endAngle: 90,
background: {
backgroundColor: "#ffff",
innerRadius: "0%",
outerRadius: "0%"
},
shape: "arc"
},
// the value axis
yAxis: {
lineWidth: 0,
tickWidth: 0,
min: -100,
max: 100,
title: {
text: "<p style='font-size: 20px; font-weight: bold'>Last 30 Days</p>",
style: {
color: "grey"
}
},
tickPositions: [-100, -20, 20, 50, 70, 90, 100],
minorTickInterval: 0,
tickAmount: 0,
plotBands: [
{
from: -100,
to: -23,
borderWidth: 5,
borderColor: "#DC143C",
color: "#DC143C",
outerRadius: "95%"
},
{
from: -20,
to: 18,
borderWidth: 5,
borderColor: "#FF4500",
color: "#FF4500",
outerRadius: "95%"
},
{
from: 21,
to: 48,
borderWidth: 5,
borderColor: "#FFFF00",
color: "#FFFF00",
outerRadius: "95%"
},
{
from: 51,
to: 68,
borderWidth: 5,
borderColor: "#00BFFF",
color: "#00BFFF",
outerRadius: "95%"
},
{
from: 71,
to: 88,
borderWidth: 5,
borderColor: "#ADFF2F",
color: "#ADFF2F",
outerRadius: "95%"
},
{
from: 91,
to: 100,
borderWidth: 5,
borderColor: "#FF1493",
color: "#FF1493",
outerRadius: "95%"
}
],
labels: {
enabled: true,
distance: 10,
rotation: 0,
format: "<span style='fill:#00000; font-size: 16px'>{value}</span>"
}
},
plotOptions: {
solidgauge: {
borderColor: "#009CE8",
borderWidth: 0,
radius: 90,
innerRadius: "90%",
dataLabels: {
enabled: true,
y: 5,
borderWidth: 0,
useHTML: true,
format:
'<div id="BackgroundColor" style="Width: 50px;text-align:center"><span style="font-size:70px;color: #000000; margin-left: -20px">{y}</span></div>'
}
}
},
series: [
{
name: "Speed",
data: [20],
animation: {
duration: 1500
}
}
]
});
I think something is wrong with how you are parsing the d attribute of the path?
Also, when you enter 100 as the data the circle is a bit short of 100?
And when you have data as 0 or 100, the circle is on the faint blue line, but otherwise, at zero (in the middle) it is off from the faint blue line:
This suggests to me that the x-position is correct but the y-position is offset negative direction (towards the top of the svg) and needs to be pushed down (translate positive y)
I changed the color to black just to see it better and then you can see with transform: 'translate(0 10)' the black circle falls perfectly on the light blue line (and also when the data is 100 it lines up with 100 correctly):
Finally, with all inner and outer radius adjusted etc. to centre it:
Note the following style is added to remove the light blue line from the chart:
<style>
.highcharts-point{
opacity: 0;
}
</style>
Probably, this translation(0 10) is needed because of this element (and its translation):
<g data-z-index="0.1" class="highcharts-series highcharts-series-0 highcharts-solidgauge-series highcharts-tracker" transform="translate(10,10) scale(1 1)" clip-path="url(#highcharts-fh3kcab-2-)"/>
Full working demo: https://jsfiddle.net/alexander_L/1yewj7r5/26/

Highcharts: render color to series dynamically

Problem: I am trying to plot a dumbel chart using highcharts. I want to conditionally check if the series is positive or negative and assign the color to the line series.
tried: to write a function to dynamically assign the colors but it does not work. But the same function is used to dynalically render circles and it work
https://jsfiddle.net/z4t2qg5o/
Highcharts.chart('container', {
chart: {
type: 'xrange'
},
plotOptions: {
columnrange: {
colorByPoint: true,
colors: ['red', 'blue', 'yellow']
}
},
title: {
text: 'Highcharts X-range'
},
xAxis: {
},
yAxis: {
title: {
text: ''
},
categories: ['Prototyping', 'Development', 'Testing'],
reversed: true
},
series: [{
// name: 'Project 3',
// pointPadding: 0,
// groupPadding: 0,
//borderColor: 'gray',
pointWidth: 5,
data: [{
x: 32,
x2: 33,
y: 0,
val: -1,
//color:'red'
// partialFill: 0.25
}, {
x: 21,
x2:25,
y: 1,
val: 1,
//color:'#BADA55'
}, {
x:31,
x2: 32,
y: 2,
val: -1,
//color:'red'
}],
dataLabels: {
align: 'left',
enabled: false
}
}]
}, function() {
var chart = this,
leftOffset = chart.plotLeft,
topOffset = chart.plotTop,
series = chart.series[0],
xAxis = series.xAxis,
x2Axis = series.x2Axis,
yAxis = series.yAxis,
points = series.points;
points.forEach(function(point) {
var x = xAxis.toPixels(point.x) - leftOffset,
x2 = xAxis.toPixels(point.x2) - leftOffset,
y = yAxis.toPixels(point.y - 0.005) - topOffset,
toCenter = x2-x;
val = point.val;
toCenter = toCenter > 0 ? toCenter : -toCenter;
if(val > 0 ){
//to set the color of the line to green
point.color = '#BADA55';
chart.renderer.circle(x, y, 6).attr({
fill: '#BADA55',
//'stroke-width': 1,
stroke: '#BADA55',
zIndex: 10
}).add(series.group);
chart.renderer.circle(x2, y, 6).attr({
fill: '#BADA55',
//'stroke-width': 1,
stroke: '#BADA55',
zIndex: 10
}).add(series.group);
// toCenter = toCenter > 0 ? toCenter : -toCenter;
chart.renderer.image('https://www.highcharts.com/samples/graphics/sun.png',x2 + 74,y +35,20,20).attr({
zIndex: 15
}).add();
}
else{
//to set the color of the line to green
point.color = '#BADA55';
chart.renderer.circle(x, y, 6).attr({
fill: '#ff0000',
'stroke-width': 1,
zIndex: 10
}).add(series.group);
chart.renderer.image('https://www.highcharts.com/samples/graphics/sun.png',x + 92,y +35,20,20).attr({
zIndex: 15
}).add();
// toCenter = toCenter > 0 ? toCenter : -toCenter;
chart.renderer.circle(x2, y , 6).attr({
fill: '#ff0000',
// 'stroke-width': 2,
zIndex: 10
}).add(series.group);
}
});
});
#container {
min-width: 300px;
max-width: 800px;
height: 300px;
margin: 1em auto;
}
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/xrange.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<div id="container"></div>
Expected: In the link shared, I want the line to be green when the 'val' is positive and the line to be red when the 'val' is negative
There might be a better way to achieve what you want. instead of writing your own function use Zones.
Look here.
You can use zones like this :
series:[{
data : [1,5,-8,9,12]//your data
zones : [{value:0,color:'red'},{color:'green'}]
}]
A live example of this is provided by HighCharts API refrence at this jsfiddle.
I don't know if this counts as an answer to your question but taking a look at this Zone thing might buy you some time.

Align a data label below a point on a bubble graph (Chart.JS)

I am trying to position a label related to the dataset below a point on a bubble graph and to have the value displayed on top of the point.
I have tried returning two different values, but it only allows me to return one.
Because of this I have returned both values within the same string.
Is it possible to return the label and position it below the value of the dataset and to put the value above the point of the dataset?
If it isn't possible would it be possible to somehow get the text to align to the center after the line break I have added to the string?
Here is what I have so far
This is what I am trying to achieve, but with the value above the bubble
Here is my code so far:
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'bubble',
data: {
datasets: [
{
label: 'Top',
data: [
{x: 110, y: 0, r: 12, name: "Performance"}
],
backgroundColor: "rgba(255,255,255,1)",
borderColor: "rgba(91,182,209,1)",
borderWidth: 2,
hoverBackgroundColor: "rgba(255,255,255,1)",
hoverBorderWidth : 2
},
{
label: 'Average',
data: [
{x: 75, y: 0, r: 12, name: "Performance"}
],
backgroundColor: "rgba(255,255,255,1)",
borderColor: "rgba(91,182,209,1)",
borderWidth: 2,
hoverBackgroundColor: "rgba(255,255,255,1)",
hoverBorderWidth : 2
},
{
label: 'You 2017',
data: [
{x: 55, y: 0, r: 15, name: "Performance"}
],
backgroundColor: "rgba(255,255,255,1)",
borderColor: "rgba(91,182,209,1)",
borderWidth: 2,
hoverBackgroundColor : "rgba(255,255,255,1)",
hoverBorderWidth : 2
},
{
label: 'You 2018',
data: [
{x: 90, y: 0, r: 15, name: "Performance"} // The labe needs to be
],
backgroundColor: "rgba(255,255,255,1)",
borderColor: "rgba(91,182,209,1)",
borderWidth: 2,
hoverBackgroundColor : "rgba(255,255,255,1)",
hoverBorderWidth : 2
}
]
},
options: {
legend: {
display: false
},
plugins: {
datalabels: {
anchor: function (context) {
var value = context.dataset.data[context.dataIndex];
return value.x < 1000 ? 'end' : 'center';
},
align: function (context) {
var value = context.dataset.data[context.dataIndex];
return value.x < 1000 ? 'end' : 'center';
},
color: function (context) {
var value = context.dataset.data[context.dataIndex];
return value.x < 1000 ? context.dataset.borderColor : 'white';
},
font: {
weight: 'bold'
},
formatter: function (value, context) {
ctx.textAlign = "center";
return context.dataset.label + "\n" + Math.round(value.x);
},
offset: 2,
padding: 0
}
},
maintainAspectRatio: false,
scales: {
yAxes: [{
id: 'first-y-axis',
type: 'linear',
ticks: {
min: 0,
max: 1,
stepSize: 1,
display: false
},
gridLines: {
display: false,
drawBorder: false
}
}],
xAxes: [
{
id: 'first-x-axis',
ticks: {
min: 50, // Controls where axis starts
max: 120, // Controls where axis finishes
stepSize: 70 // Control the gap between the first x-axis value and the last x-axis value
},
gridLines: {
display: false,
lineWidth: 3 // Width of bottom line
}
}
]
}
}
});
Any help or suggestions would be greatly appreciated ^_^
I figured this out by applying 'textAlign' within the charts parameters and set it to centre.
You can see this in the code below:
plugins: {
datalabels: {
anchor: function (context) {
var value = context.dataset.data[context.dataIndex];
return value.x < 1000 ? 'end' : 'center';
},
align: function (context) {
var value = context.dataset.data[context.dataIndex];
return value.x < 1000 ? 'end' : 'center';
},
color: function (context) {
var value = context.dataset.data[context.dataIndex];
return value.x < 1000 ? context.dataset.borderColor : 'white';
},
textAlign: 'center',
font: {
weight: 'bold',
alignment: 'right' // Is this the place to be doing this?
},
formatter: function (value, context) {
return context.dataset.label + '\n' + Math.round(value.x);
},
offset: 2,
padding: 0
}
},
Hope this helps ^^

Categories

Resources