SVG as labels in HighChart stacked column chart - javascript

I'm trying to create a stacked column chart in highchart, with the x-axis labels being SVG-images as shown on this image:
I've gotten it to work with single data points per label (ie non-stacked data), but as soon I change the input data to an array, the data stops rendering.
This "works":
https://jsfiddle.net/jakobhl/krx4e5pm/2/
var dataName = function(imgSrc) {
return '<span><img src=' + imgSrc + ' ' + 'style="width: 40px; height: 40px;"/><br></span>';
};
var data2016 = [
[11, dataName("https://image.flaticon.com/icons/svg/197/197571.svg")],
[11, dataName("https://image.flaticon.com/icons/svg/197/197408.svg")],
[11, dataName("https://image.flaticon.com/icons/svg/197/197375.svg")],
[14, dataName("https://image.flaticon.com/icons/svg/197/197374.svg")],
[12, dataName("https://image.flaticon.com/icons/svg/197/197484.svg")],
];
Highcharts.chart('container', {
chart: {
type: 'column'
},
plotOptions: {
column: {
stacking: 'normal',
dataLabels: {
enabled: true
}
}
},
xAxis: {
tickmarkPlacement: 'on',
lineWidth: 0,
type: 'category',
labels: {
useHTML: true,
align: 'center'
}
},
series: [{
keys: ['y', 'name'],
data: data2016,
}]
});
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/highcharts-more.js"></script>
<div id="container"></div>
This does not:
https://jsfiddle.net/jakobhl/2rfa645x/3/
var dataName = function(imgSrc) {
return '<span><img src=' + imgSrc + ' ' + 'style="width: 40px; height: 40px;"/><br></span>';
};
var data2016 = [
[[11, 15], dataName("https://image.flaticon.com/icons/svg/197/197571.svg")],
[[12, 15], dataName("https://image.flaticon.com/icons/svg/197/197408.svg")],
[[13, 15], dataName("https://image.flaticon.com/icons/svg/197/197375.svg")],
[[41, 15], dataName("https://image.flaticon.com/icons/svg/197/197374.svg")],
[[11, 15], dataName("https://image.flaticon.com/icons/svg/197/197484.svg")],
];
Highcharts.chart('container', {
chart: {
type: 'column'
},
plotOptions: {
column: {
stacking: 'normal',
dataLabels: {
enabled: true
}
}
},
xAxis: {
tickmarkPlacement: 'on',
lineWidth: 0,
type: 'category',
labels: {
useHTML: true,
align: 'center'
}
},
series: [{
keys: ['y', 'name'],
data: data2016,
}]
});
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/highcharts-more.js"></script>
<div id="container"></div>
How can I get the data to stack per country while still using SVGs as labels?
Thanks to the jsfiddle user BlackLabel for inspiration.

You can add another value, but you need to adapt the data format required by Highcharts. If the new value is x, just do it as below:
var data2016 = [
[
11, 15, dataName("https://image.flaticon.com/icons/svg/197/197571.svg")
],
...
];
Highcharts.chart('container', {
...,
series: [{
keys: ['y', 'x', 'name'],
data: data2016
}]
});
Live demo: https://jsfiddle.net/BlackLabel/vubjn8od/
API Reference: https://api.highcharts.com/highcharts/series.column.keys

I never found out why the original solution didn't work, but a working solution was to use categories instead of series:
https://jsfiddle.net/jakobhl/L3hzeqpv/1/
var dataName = function(imgSrc) {
return '<span><img src=' + imgSrc + ' ' + 'style="width: 40px; height: 40px;"/><br></span>';
};
Highcharts.chart('container', {
chart: {
type: 'column'
},
title: {
text: 'Stacked column chart'
},
xAxis: {
labels: {
useHTML: true,
align: 'center'
},
categories: [dataName("https://image.flaticon.com/icons/svg/197/197571.svg"), dataName("https://image.flaticon.com/icons/svg/197/197408.svg"), dataName("https://image.flaticon.com/icons/svg/197/197375.svg"), dataName("https://image.flaticon.com/icons/svg/197/197374.svg"), dataName("https://image.flaticon.com/icons/svg/197/197484.svg")]
},
yAxis: {
min: 0,
title: {
text: 'Total fruit consumption'
},
stackLabels: {
enabled: true,
style: {
fontWeight: 'bold',
color: ( // theme
Highcharts.defaultOptions.title.style &&
Highcharts.defaultOptions.title.style.color
) || 'gray'
}
}
},
legend: {
align: 'right',
x: -30,
verticalAlign: 'top',
y: 25,
floating: true,
backgroundColor:
Highcharts.defaultOptions.legend.backgroundColor || 'white',
borderColor: '#CCC',
borderWidth: 1,
shadow: false
},
tooltip: {
headerFormat: '<b>{point.x}</b><br/>',
pointFormat: '{series.name}: {point.y}<br/>Total: {point.stackTotal}'
},
plotOptions: {
column: {
stacking: 'normal',
dataLabels: {
enabled: true
}
}
},
series: [{
name: 'John',
data: [5, 3, 4, 7, 2]
}, {
name: 'Jane',
data: [2, 2, 3, 2, 1]
}, {
name: 'Joe',
data: [3, 4, 4, 2, 5]
}]
});
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/highcharts-more.js"></script>
<div id="container"></div>

Related

customized tooltip and linking values to formfields -- highcharts / columnrange

High everyone,
I am trying to get two things to happen. First, I want to create a custom tooltip for a columnrange-type series where the tooltip shows something like HIGH: 'this.point.high' and on a new line "LOW:" 'this.point.low'. Second, I would like these 'low' and 'high' values to populate a form field dynamically. For example, when a user drags the high value for the columnrange entry, I want this to dynamically update a number in the corresponding formfield that collects user input.
Here is a fiddle: https://jsfiddle.net/e9zqmy12/
Code:
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/highcharts-more.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<script src="https://code.highcharts.com/modules/export-data.js"></script>
<script src="https://code.highcharts.com/modules/accessibility.js"></script>
<script src="https://code.highcharts.com/modules/draggable-points.js"></script>
<figure class="highcharts-figure">
<div id="container"></div>
</figure>
var myChart;
Highcharts.setOptions({
plotOptions: {
series: {
animation: false
}
}
});
// draw chart
myChart = Highcharts.chart('container',
{
chart: {
type: "line",
events: {
click: function (e) {
// find the clicked values and the series
var y = Math.round(e.yAxis[0].value),
x=12
series = this.series[3].data[12];
series.update({x, y, color: 'blue'});
},
drag: function (e) {
var y = Math.round(e.yAxis[0].value),
x=12
series = this.series[3].data[12];
series.update({x, y, color: 'blue'});
}
}
},
title: {
text: "Forecasting History"
},
xAxis: {
type: 'category',
allowDecimals: true,
title: {
text: "Quarter"
},
plotBands: [{
color: 'rgba(204,153,255,0.2)', // Color value
from: 11.5, // Start of the plot band
to: 12.5, // End of the plot band
label: {
text: 'Forecast'
}
}]
},
yAxis: {
title: {
text: "Inflation (%)"
},
plotLines: [{
value: 0,
width: 2,
color: '#aaa',
zIndex: 10
}]
},
tooltip: {
style: {
color: 'black',
fontWeight: 'bold',
fontSize: 13
},
positioner: function () {
return { x: 80, y:0 };
},
shared: true,
headerFormat: '',
valueDecimals: 2,
shadow: false,
borderWidth: 2,
borderColor: '#000000',
shape: 'rect',
backgroundColor: 'rgba(255,255,255,0.8)'
},
series: [
{
name: 'Inflation',
data: [3.9,4.98,5.72,5.73,3.61,3.68,3.72,2.64,2.1,1.94,1.99,1.87,null],
tooltip: {
pointFormat: '{series.name}: <b>{point.y}%</b><br/>',
},
},{
name: 'Central Bank Forecast',
data: [2,3.47,4.2,4.62,4.51,3.079,3.13,3.15,2.43,2.17,1.7,2.17,null],
tooltip: {
pointFormat: '{series.name}: <b>{point.y}%</b><br/>',
},
},{
name: 'Your Forecast',
showInLegend: false,
data: [null,null,null,null,null,null,null,null,null,null,null,null,2],
tooltip: {
pointFormat: '{series.name}: <b>{point.y}%</b><br/>',
},
marker: {
radius: 2.5,
fillColor: 'red'
},
},{
plotOptions: {
columnrange: {
dataLabels: {
enabled: true,
}
}
},
name: 'Forecast Range',
color: 'rgba(255,0,0,.1)',
type: 'columnrange',
data: [[12,1,3]],
tooltip: {
pointFormatter: function() {
console.log(this);
return "LOW: "+this.point.low + " HIGH:" +this.point.high;
}
},
dragDrop: {
draggableY: true,
groupBy: 'GroupId',
dragMinY: -10,
dragMaxY: 10,
dragPrecisionY: .01,
liveRedraw: false
},
}
],
});
It seems that your code was almost good except this callback pointFormatter callback - notice that this calls for point already, so this.point refers to undefined, it should be:
tooltip: {
pointFormatter: function() {
console.log(this);
return "LOW: " + this.low + " <br>HIGH:" + this.high;
}
},
Demo: https://jsfiddle.net/BlackLabel/vbo6j9em/

numbers are too long to show correctly in highcharts/javascript

I have a weird question:
The series1 variable is an array of date-times, which are too long. Because of this, the chart cannot display correctly. However, if I change series1 to make it contain the values of series2. It will work correctly. Can you let me know what I should do?
Also, how can I get each value in series1 shown as a date? suppose it is a variable from flask {{series1}}. thank you.
$(function () {
var series1 = [1489298400000L, 1492923600000L, 1492318800000L, 1480226400000L, 1494133200000L, 1490504400000L, 1488088800000L, 1475384400000L, 1493528400000L, 1491109200000L, 1480831200000L, 1471755600000L]
var series2 = [1, 7, 2, 1, 4, 1, 1, 1, 4, 6, 1, 1]
var series3 = [102, 95, 110, 111, 81, 104, 99, 92, 90, 100, 103, 98]
var myChart =
Highcharts.chart('container', {
chart: {
zoomType: 'xy'
},
title: {
text: 'Average Monthly Temperature and Rainfall in Tokyo'
},
credits: {
text: 'Songhuiming',
href: 'http://www.songhuiming.com'
},
subtitle: {
text: 'Source: WorldClimate.com'
},
xAxis: [{
categories: series1,
crosshair: true
}],
yAxis: [{ // Primary yAxis
labels: {
format: '{value}°C',
style: {
color: Highcharts.getOptions().colors[1]
}
},
title: {
text: 'Temperature',
style: {
color: Highcharts.getOptions().colors[1]
}
}
}, { // Secondary yAxis
title: {
text: 'Rainfall',
style: {
color: Highcharts.getOptions().colors[0]
}
},
labels: {
format: '{value} mm',
style: {
color: Highcharts.getOptions().colors[0]
}
},
opposite: true
}],
tooltip: {
shared: true
},
legend: {
layout: 'vertical',
align: 'left',
x: 120,
verticalAlign: 'top',
y: 100,
floating: true,
backgroundColor: (Highcharts.theme && Highcharts.theme.legendBackgroundColor) || '#FFFFFF'
},
series: [{
name: 'Rainfall',
type: 'column',
yAxis: 1,
data: series2,
tooltip: {
valueSuffix: ' mm'
}
}, {
name: 'Temperature',
type: 'spline',
data: series3,
tooltip: {
valueSuffix: '°C'
}
}]
});
});
About suffix "L" on the end you can read here.
What you need at first to make all items in series1 array be a string, because as it now, you will have an error. Then remove "L" and convert to dates
let series = ['1489298400000L', '1492923600000L', '1492318800000L', '1480226400000L', '1494133200000L', '1490504400000L', '1488088800000L', '1475384400000L', '1493528400000L', '1491109200000L', '1480831200000L', '1471755600000L'];
let series1 = series.map((item) => {
let date = new Date(parseInt(item.replace("L", ""))));
return `${date.getMonth()} ${date.getFullYear()}`;
});

How to set object value in color attribute for high charts legends?

I have to set dynamic text colors based on some condition for legend , In below picture there is some legends like "New" , "Impact Assessment", "Stackholder Review" etc. So all legends had associated with stacks like first 4 associated with X entity and rest associated with Y entity. For X entity I need to change text color in Green and for Y Red Color.
legend: {
layout: 'horizontal',
align: 'left',
verticalAlign: 'bottom', borderWidth: 0, enabled: true,
x: -2, y: 7,
symbolWidth: 4, symbolHeight: 4,
itemStyle: {
'cursor': 'default',
fontSize: '10px',
color: 'Red'
}
},
series: formatChartData(ctrl.TeamData)
});
**color : "Defect" ? 'Red' : 'Green'**
Above Statement is fine and giving the correct color of legends but here "Defect" is static value , I need it take from dynamic value?
Problem I am not able to set dynamic value.
Solution
legend: {
labelFormatter: function () {
var color = this.options.stack == 'Male' ? '#AB1133' : '#02A202';
return '<span style="color:' + color + '">' + this.name + '</span>';
}
}
Above solution also working
As discussed check answer below .
I am using chart events load function to modify legend text color
Highcharts.chart('container', {
chart: {
type: 'column',
events: {
load: function() {
var seriesData = this.series;
for (var i = 0; i < seriesData.length; i++) {
//checks the stack type
if (seriesData[i].options.stack == 'male') {
/*update the legend fonts*/
this.legend.allItems[i].legendItem.css({
color: 'red',
fill: 'red',
});
}
if (seriesData[i].options.stack == 'female') {
this.legend.allItems[i].legendItem.css({
color: 'green',
fill: 'green',
});
}
}
}
}
},
title: {
text: 'Total fruit consumtion, grouped by gender'
},
xAxis: {
categories: ['Apples', 'Oranges', 'Pears', 'Grapes', 'Bananas']
},
yAxis: {
allowDecimals: false,
min: 0,
title: {
text: 'Number of fruits'
}
},
tooltip: {
formatter: function() {
return '<b>' + this.x + '</b><br/>' +
this.series.name + ': ' + this.y + '<br/>' +
'Total: ' + this.point.stackTotal;
}
},
plotOptions: {
column: {
stacking: 'normal'
}
},
series: [{
name: 'John',
data: [5, 3, 4, 7, 2],
stack: 'male',
//color: 'red'
}, {
name: 'Joe',
data: [3, 4, 4, 2, 5],
stack: 'male',
//color: 'red'
}, {
name: 'Jane',
data: [2, 5, 6, 2, 1],
stack: 'female',
//color: 'green',
}, {
name: 'Janet',
data: [3, 0, 4, 4, 3],
stack: 'female',
//color: 'green'
}]
});
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<div id="container" style="min-width: 310px; height: 400px; margin: 0 auto"></div>
update
Able to disable font color change onmouseover and onmouseout.
onclick functionality if removed, then font color doesn't change and vice-versa
Highcharts.chart('container', {
chart: {
type: 'column',
events: {
load: function() {
var seriesData = this.series;
for (var i = 0; i < seriesData.length; i++) {
if (seriesData[i].options.stack == 'male') { //checks the stack
/*update the legend fonts*/
this.legend.allItems[i].legendItem.css({
color: 'red',
fill: 'red',
});
}
if (seriesData[i].options.stack == 'female') {
this.legend.allItems[i].legendItem.css({
color: 'green',
fill: 'green',
});
}
}
}
}
},
title: {
text: 'Total fruit consumtion, grouped by gender'
},
xAxis: {
categories: ['Apples', 'Oranges', 'Pears', 'Grapes', 'Bananas']
},
yAxis: {
allowDecimals: false,
min: 0,
title: {
text: 'Number of fruits'
}
},
tooltip: {
formatter: function() {
return '<b>' + this.x + '</b><br/>' +
this.series.name + ': ' + this.y + '<br/>' +
'Total: ' + this.point.stackTotal;
}
},
plotOptions: {
column: {
stacking: 'normal'
}
},
series: [{
name: 'John',
data: [5, 3, 4, 7, 2],
stack: 'male',
//color: 'red'
}, {
name: 'Joe',
data: [3, 4, 4, 2, 5],
stack: 'male',
//color: 'red'
}, {
name: 'Jane',
data: [2, 5, 6, 2, 1],
stack: 'female',
//color: 'green',
}, {
name: 'Janet',
data: [3, 0, 4, 4, 3],
stack: 'female',
//color: 'green'
}]
}, function(chart) {
$.each(chart.series, function(i, series) {
/* comment onclick. for onclick functionality*/
series.legendGroup.element.onmouseover = null;
series.legendGroup.element.onmouseout = null;
series.legendGroup.element.onclick = null;
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<div id="container" style="min-width: 310px; height: 400px; margin: 0 auto"></div>

how to pass data to next page in HighCharts?

currently i doing Highchart in ColdFusion. I want to pass my data in Highchart to next page when i click on the x-axis' label. The charts i doing is spiderweb. For a scenario,i have x-axis label like 'Overall','Appt Booking', 'Reception', 'Service Advisor', 'Completion Delivery Process'. When i click on overall, the data in overall axis are pass to next page in the link i going. So anyone can guide me how to do it? I manage to link to the page i want,now i just dunno how to get the data to pass to next page.
Below is my code,TQ.
<cfscript>
categories= ['Overall','Appt Booking', 'Reception', 'Service Advisor', 'Completion Delivery Process'] ;
series = [{
'name': 'Last Month',
'data': [3.775,3.5, 3.9, 4, 3.7],
'pointPlacement': 'on'
}, {
'name': 'MTD',
'data': [ 3.775, 3.7, 3.5, 3.9, 4],
'pointPlacement': 'on'
}, {
'name': 'Target',
'data': [3.725, 3.8,3.5, 3.7, 3.9],
'pointPlacement': 'on',
'url': 'https://www.google.com/'
}];
</cfscript>
<html>
<head>
<script src="jquery.min.js"></script>
<script src="highcharts.js"></script>
<script src="exporting.js"></script>
<script src="highcharts-more.js"></script>
<script>
$(function () {
var categoryLinks = {
'Overall': 'http://127.0.0.1:8500/highCharts/Spiderweb.cfm?id=1234',
'Appt Booking': 'http://127.0.0.1:8500/highCharts/line.cfm',
'Service Advisor': 'http://127.0.0.1:8500/highCharts/combine.cfm'
};
$('#container').highcharts({
chart: {
polar: true,
type: 'line'
},
title: {
text: 'Budget vs spending',
x: -1000
},
pane: {
size: '70%'
},
xAxis: {
categories: <cfoutput>#serializeJson(categories)#</cfoutput>,
tickmarkPlacement: 'on',
lineWidth: 0,
labels: {
formatter: function () {
return '<a href="' + categoryLinks[this.value] + '">' +
this.value + '</a>';
}
}
},
yAxis: [{
gridLineInterpolation: 'polygon',
lineWidth: 0,
min: 3,
endOnTick: true,
showLastLabel: true,
tickPositions: [3,3.5, 4, 4.5, 5],
}],
plotOptions: {
series: {
cursor: 'pointer',
point: {
events: {
click: function () {
alert('Category: ' + this.category + ', value: ' + this.y);
}
}
}
}
},
tooltip: {
shared: true,
pointFormat: '<span style="color:{series.color}">{series.name}: <b>{point.y:,.2f}</b><br/>'
},
legend: {
align: 'right',
verticalAlign: 'top',
y: 70,
layout: 'vertical'
},
series: <cfoutput>#serializeJson(series)#</cfoutput>
});
});
</script>
</head>
<body>
<div id="container" style="min-width: 400px; max-width: 600px; height: 400px; margin: 0 auto"></div>
</body>
</html>
Try using:
labels: {
formatter: function () {
location.href = categoryLinks[this.value];
}
}
instead of:
return '' + this.value + '';`

Add series total to legend in Highcharts

Using Highcharts.js - I want to add the series total to the legend (where it currently says '12345'). I know enough that I need to write a labelFormatter function, but I don't know enough JavaScript to figure out how to sum up the total of each series. Code is below (also live version here: http://jsbin.com/ukabob/8).
$(function () {
var chart;
$(document).ready(function() {
chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'line',
backgroundColor: '#E9E7DC',
borderRadius:0,
margin: [0, 150, 30, 0]
},
colors: ['#A74B59', '#46C4B7', '#EDBA70'],
credits: {
enabled: false
},
title: {
text: null
},
xAxis: {
categories: ['2013', '2014', '2015', '2016', '2017', '2018',
'2019', '2020', '2021', '2022'],
gridLineWidth:1,
gridLineColor: '#FFFFFF',
labels: {
style: {
color: '#000000'
},
formatter: function() {
return '<div style="font-size:22px; font-family: \'Advent Pro\', sans-serif;">'+
this.value +'</div>';
},
y:25
},
lineColor: '#FFFFFF',
tickColor: '#FFFFFF',
tickLength: 30
},
yAxis: {
gridLineWidth:0,
title: {
text: null
},
labels: {
enabled: false
}
},
plotOptions: {
series: {
marker: {
radius: 6,
lineWidth: 2,
lineColor: null, // inherit from series
symbol: 'circle',
states: {
hover: {
fillColor: '#E9E7DC',
lineWidth: 2,
radius:6
}
}
},
states: {
hover: {
lineWidth:4
}
}
}
},
tooltip: {
borderWidth:0,
borderRadius: 0
},
legend: {
borderRadius:0,
backgroundColor: '#FFFFFF',
itemMarginBottom: 7,
layout: 'vertical',
align: 'right',
verticalAlign: 'top',
y: 30,
x: 2,
borderWidth: 0,
width:130,
symbolPadding: 10,
useHTML:true,
shadow: {
color: '#000',
width: 3,
opacity: 0.15,
offsetY: 2,
offsetX: 1
},
labelFormatter: function() {
return '<div class="' + this.name + '-arrow"></div><span style="font-family: \'Advent Pro\', sans-serif; font-size:16px">' + this.name +'</span><br/><span style="font-size:10px; color:#ababaa">(Total: 12345)</span>';
}
},
series: [{
name: 'Honeywell',
data: [700,725,750,850,950,1000,1025,1050,1050,1050]
}, {
name: 'Bombardier',
data: [661,758,880,990,1065,1136,1193,1241,1289,1335]
}, {
name: 'Embraer',
data: [747,789,839,861,890,908,984,1030,1097,1156]
}]
});
});
});
A more generic & dynamic answer:
legend: {
labelFormatter: function() {
var total = 0;
for(var i=this.yData.length; i--;) { total += this.yData[i]; };
return this.name + '- Total: ' + total;
}
}
Figured it out. I added the total to the series, then called it with this.options. See updated code below:
legend: {
borderRadius:0,
backgroundColor: '#FFFFFF',
itemMarginBottom: 7,
layout: 'vertical',
align: 'right',
verticalAlign: 'top',
y: 30,
x: 2,
borderWidth: 0,
width:130,
symbolPadding: 10,
useHTML:true,
shadow: {
color: '#000',
width: 3,
opacity: 0.15,
offsetY: 2,
offsetX: 1
},
labelFormatter: function() {
return '<div class="' + this.name + '-arrow"></div><span style="font-family: \'Advent Pro\', sans-serif; font-size:16px">' + this.name +'</span><br/><span style="font-size:10px; color:#ababaa">(Total: ' + this.options.total + ')</span>';
}
},
series: [{
name: 'Honeywell',
total: 9150,
data: [700,725,750,850,950,1000,1025,1050,1050,1050]
}, {
name: 'Bombardier',
total: 10548,
data: [661,758,880,990,1065,1136,1193,1241,1289,1335]
}, {
name: 'Embraer',
total: 9301,
data: [747,789,839,861,890,908,984,1030,1097,1156]
}]
});
});

Categories