Here is an example of a graph I'm using: http://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/stock/demo/basic-line/
Below it I have a table I need to update when the dates are changes (either with the draggable range at the bottom or manually inputed in input boxes not shown in this example).
Here's my dummied down code concerning the chart
const PageLineChart = props => {
let data = [];
const { title,
heading,
subtitle,
legend,
defaultRange,
xLabel,
yLabel
} = props.column;
var selected;
defaultRange
? selected = ['1m', '3m', '6m', 'ytd', '1y', 'all'].indexOf(defaultRange)
: selected = 3;
const series = props.column.values.map(field => {
return {
name: field,
data: [],
tooltip: {
valueDecimals: 2
}
};
});
props.data.map((row, index) => {
const timeStamp = moment(row[props.column.category]).unix() * 1000;
props.column.values.forEach((field, index) => {
series[index].data.push([timeStamp, Number(row[field])]);
});
});
data.reverse();
const chartConfig = {
rangeSelector: {
selected
},
credits: {
enabled: false
},
exporting: {
enabled: false
},
title: {
text: title
},
subtitle: {
text: subtitle
},
xAxis: {
title: {
text: xLabel || ''
}
},
yAxis: {
title: {
text: yLabel || ''
}
},
tooltip: {
formatter: function() {
var s = '<span style="font-size: 10px">' + moment(this.x).format('MMMM Do YYYY') + '</span><br/>';
for (var i = 0; i < this.points.length; i++) {
var prefix = '';
if (props.column.hasOwnProperty('format')) {
prefix = formatNumber(this.points[i].y, props.column.format);
} else {
prefix = formatNumber(this.points[i].y);
}
var myPoint = this.points[i];
s += '<br/><span style="color:' +
myPoint.series.color +
'">\u25CF</span> ' +
capitalize(myPoint.series.name) + ': ';
/* Need to check whether or not we are dealing with an
* area range plot and display a range if we are
*/
if (myPoint.point.low && myPoint.point.high) {
s += myPoint.point.low + ' - ' + myPoint.point.high;
} else {
s += prefix;
}
}
return s;
}
},
plotOptions: {
series: {
animation: true
}
},
shared: true,
series: series
};
return (
<div className="panel panel-default no-bg b-a-2 b-gray-dark">
<div className="panel-heading">
{heading}
</div>
<div className="panel-body">
<HighStock config={chartConfig} />
</div>
</div>
);
};
Preferably I would have liked a function that fires when changing dates and has access to the 'startDate' and 'endDate' but I can't seem to find anything in the docs.
Does anyone have any ideas please?
use setExtremes -
Fires when the minimum and maximum is set for the axis, either by calling the .setExtremes() method or by selecting an area in the chart. One parameter, event, is passed to the function. This contains common event information based on jQuery or MooTools depending on which library is used as the base for Highcharts.
Highcharts.stockChart('container', {
xAxis: {
events: {
setExtremes: function (e) {
$('#report').html('<b>Set extremes:</b> e.min: ' + Highcharts.dateFormat(null, e.min) +
' | e.max: ' + Highcharts.dateFormat(null, e.max) + ' | e.trigger: ' + e.trigger);
}
}
},
rangeSelector: {
selected: 1
},
series: [{
name: 'USD to EUR',
data: usdeur
}]
});
reference
Example demo
Related
I'm struggling with a very strange problem using Highcharts Sunburst.
Before all, keep in mind that I've validate my JSON and test it in the JSFiddle demo (find in the documentation), everything works fine.
Here's my problem :
I get my data like that :
var data = sessionStorage.getItem('data_fap');
var parsed_data = JSON.parse(data);
var chart_data = parsed_data.data;
( My JSON look like : {data: [{id: "0", parent: "", name: " ", desc: " ", value: " "},...]} )
If a used chart_data in the chart constructor, no chart, no error.
If I set my var this way :
var data = [{id: "0", parent: "", name: " ", desc: " ", value: " "},...]};
And use it in the chart constructor, everything works fine.
I was thinking it could come from my graph options so I copy/paste the one from JSFiddle, still not working...
Here's my complete chart generation code :
var data = sessionStorage.getItem('data_fap');
var parsed_data = JSON.parse(data);
var new_data = parsed_data.data;
// Splice in transparent for the center circle
Highcharts.getOptions().colors.splice(0, 0, 'transparent');
Highcharts.chart('graph_metier', {
chart: {
height: '100%'
},
title: {
text: 'Domaines et familles professionnels'
},
subtitle: {
text: ''
},
series: [{
type: "sunburst",
data: new_data,
allowDrillToNode: true,
cursor: 'pointer',
dataLabels: {
format: '{point.name}',
filter: {
property: 'innerArcLength',
operator: '>',
value: 16
}
},
levels: [{
level: 1,
levelIsConstant: false,
levelSize: {
unit: 'percentage',
value: 30
}
},{
level: 2,
colorByPoint: true
},
{
level: 3,
colorByPoint: true
}]
}],
plotOptions: {
series: {
events: {
click: function (event) {
if(event.point.parent != "0"){
}
}
}
}
},
tooltip: {
formatter: function(e){
if(e.chart.hoverPoint.options.id == 0){
return false;
}
else
{
return '<b>' + e.chart.hoverPoint.options.name + '</b> (code: ' + e.chart.hoverPoint.options.id + ')<br>' + e.chart.hoverPoint.options.desc;
}
}
}
});
If anyone could help me to understand this mess, I'll be infinitely grateful :)
i am using highcharts bar with negative stack, problem is when i hover over the left side of the chart that is in red color it shows the correct disease name that is "TB Suspect" but when i hover over the blue bar it shows the same "TB Suspect" disease which is wrong, it should show "Otitis Media"
same problem for all other diseases
Here is the code
<script>
$(function () {
if($('#disease-bar').length > 0){
// Age categories
var categories_c = [<?=$comm_disease_title?$comm_disease_title:0;?>];
var categories_nc = [<?=$non_comm_disease_title?$non_comm_disease_title:0;?>];
$(document).ready(function () {
$('#disease-bar').highcharts({
colors: ['#dd4c39', '#00a9e9', '#c61a7e', '#bd8030', '#949293', '#075290', '#7db6ed', '#009451', '#c84433'],
chart: {
type: 'bar',
backgroundColor: null
},
title: {
text: 'Top Five Communicable & Non-communicable Diseases'
},
xAxis: [{
categories: categories_c,
reversed: false,
crosshair: true,
labels: {
step: 1
}
}, { // mirror axis on right side
opposite: true,
reversed: false,
categories: categories_nc,
linkedTo: 0,
labels: {
step: 1
}
}],
yAxis: {
title: {
text: null
},
labels: {
formatter: function() {
var s = Math.abs(this.value);
if (s.toFixed(0) >= 1000000) {
return s.toFixed(0) / 1000000 + 'M';
} else {
return s.toFixed(0) / 1000 + 'K';
}
}
}
},
plotOptions: {
series: {
cursor: 'pointer',
stacking: 'normal',
//point: {
events: {
click: function () {
//alert(this.name);return;
if(this.name=="Communicable"){
var url = 'disease.php<?=$next_url;?>&module=1';
}
else {
var url = 'disease.php<?=$next_url;?>&module=2';
}
//alert(url);
location.href = url;
}
,legendItemClick: function (event) {
//console.log(event.target.visible);
if(event.target.name=='Communicable'){
if(event.target.visible){this.chart.xAxis[0].update({
labels: {
enabled: false
}
});}
else {this.chart.xAxis[0].update({
labels: {
enabled: true
}
});}
}
else {
if(event.target.visible){this.chart.xAxis[1].update({
labels: {
enabled: false
}
});}
else {this.chart.xAxis[1].update({
labels: {
enabled: true
}
});}
}
//console.log(event.target.name);
//console.log(this.chart.xAxis[0]);
}
}
// }
}
},
tooltip: {{
formatter: function () {
return '<b>' + this.point.category + '</b><br/>' +
'Diseases: <b>' + Math.abs(this.point.y) +'</b>';
}
},
exporting: {
//enabled: false
},
credits: {
enabled: false
},
series: [{
name: 'Communicable',
data: [<?=$comm_disease_value?$comm_disease_value:0;?>]
}, {
name: 'Non-communicable',
data: [<?=$non_comm_disease_value?$non_comm_disease_value:0;?>]
}]
});
});
}
});
</script>
Here is the tooltip code which i am using
tooltip: {{
formatter: function () {
return '<b>' + this.point.category + '</b><br/>' +
'Diseases: <b>' + Math.abs(this.point.y) +'</b>';
}
},
JS Fiddle : https://jsfiddle.net/hamza9/h1nrn9nu/
I was able to get the correct category from the formatter:
formatter: function() {
var subCategoryLabel = this.series.chart.xAxis[this.series._i]
.categories[this.point.index];
return '<b>' + subCategoryLabel + '</b><br/>' +
'Diseases: <b>' + Math.abs(this.point.y) + '</b>';
}
You have to modify series data as array of object, wheredd is respective categories name and y is the value
series: [{
name: 'Communicable',
data: [{y:-1489599,dd:'Acute (Upper) Respiratory Infections'}, {y:-256548,dd:'Scabies'}, {y:-157531,dd:'Diarrhoea / Dysentery < 5 yrs'}, {y:-148696,dd:'Diarrhoea / Dysentery > 5 yrs'}, {y:-86283,dd:'Worm Infestations'}]
//url: 'disease.php?frequency=m&year=2017&month=1&quarter=&fatype=&disease_cat=comm'
}, {
name: 'Non-communicable',
data: [{y:399786,dd:'Fever due to other causes'}, {y:247500,dd:'Peptic Ulcer Diseases'}, {y:196653,dd:'Hypertension'}, {y:176866,dd:'Dental Caries'}, {y:169514,dd:'Diabetes Mellitus'}]
//url: 'disease.php?frequency=m&year=2017&month=1&quarter=&fatype=&disease_cat=noncomm'
}]
In your tooltip you can access it via the "point" attribute of the object passed in:
tooltip: {
formatter: function() {
return '<b>' + this.point.dd + '</b><br/>' +
'Diseases: <b>' + Math.abs(this.point.y) + '</b>';
}
},
Fiddle demo
Simply get rid of the linkedTo property from the second xAxis and link 'Non-Communicable' series to 1 xAxis.
API Reference:
http://api.highcharts.com/highcharts/series%3Cbar%3E.xAxis
Example:
https://jsfiddle.net/yqe0kunn/
I'm using ECharts in order to create dynamically some line charts.
They are created within div which are dynamically created in my js script based on the server response. The problem is that they are not shown.
I did some test and I noticed that if a div has height 0, the chart will not be shown. So I moved the charts initialization when the div is visible: also now I can't see anything.
var chartsIds = []; // div id list
var lineCharts = []; // charts array
var optionLineCharts = [];
this is the charts initialization function
function init_echart(id, index) {
if ($("#" + id).length) {
var echartLine = echarts.init(document.getElementById(id), theme);
echartLine.setOption(optionLineCharts[index], true);
lineCharts.push(echartLine);
}
}
which is called for each div id in this moment if ($("#block").is(":visible")).
The options are like this one:
var echartLineOptions = {
tooltip:
{
trigger: "item",
formatter: function(params) {
var date = new Date(params.value[0]);
data = date.getFullYear() +
"-" +
(date.getMonth() + 1) +
"-" +
date.getDate() +
" " +
date.getHours() +
":" +
date.getMinutes();
return data + "<br/>" + params.value[1];
}
},
legend:
{
data: []
},
toolbox:
{
show: true,
feature: {
mark: { show: true },
dataView: { show: true, readOnly: false },
restore: { show: true },
saveAsImage: { show: true }
}
},
dataZoom: {
show: true,
start: 70
},
xAxis: [
{
type: "time",
splitNumber: 2
}
],
yAxis: [
{
type: "value"
}
],
series:
[]
};
where the series are populated (correctly) based on the server response. I can see with the debug all the data and the series.
I noticed that even if the biggest div is visible, the div created by the charts initialization function has height = 0. I can't find any solutions..any help is really appreciated!!
The code of my graph is this (take data from a php page and then adds some series):
$('#grafico_1').highcharts({
chart: {
type: 'line',
zoomType: 'xy',
animation : false,
events: {
selection: function(event) {
if(event.resetSelection){
setTimeout(function(e){
var chart = $('#grafico_1').highcharts();
var extreme = chart.yAxis[0].getExtremes();
var mio_min = parseFloat(proprieta_temperatura_aperto[34]);
var mio_max = parseFloat(proprieta_temperatura_aperto[35]);
if(extreme.dataMin < mio_min){
mio_min = extreme.dataMin;
}
if(extreme.dataMax > mio_max){
mio_max = extreme.dataMax;
}
chart.yAxis[0].setExtremes(mio_min,mio_max);
$("#temperatura_min_max_rilevato").html("Min "+extreme.dataMin+"°C - Max "+extreme.dataMax+"°C");
//console.log("zoom - ");
}, 10);
}else{
setTimeout(function(e){
var chart = $('#grafico_1').highcharts();
var extreme = chart.yAxis[0].getExtremes();
$("#temperatura_min_max_rilevato").html("Min "+extreme.dataMin+"°C - Max "+extreme.dataMax+"°C");
//console.log("zoom + "+JSON.stringify(extreme));
}, 50);
}
}
},
},
credits : {
enabled : false
},
title: {
text: 'Grafico di Oggi'
},
xAxis: {
type: 'datetime',
title: {
text: false
}
},
yAxis: [
{
title: {
text: false
},
labels: {
format: '{value}°C',
},
//ceiling : parseFloat(proprieta_temperatura_aperto[35]),
//floor: parseFloat(proprieta_temperatura_aperto[34]),
max : parseFloat(proprieta_temperatura_aperto[35]),
min: parseFloat(proprieta_temperatura_aperto[34]),
},
{
title: {
text: false
},
min: 0,
max : 1,
ceiling:1,
floor : 0,
//tickLength : 1,
opposite: true,
tickInterval: 1,
labels: {
formatter: function() {
if (this.value == 0 || this.value == 1){
return this.value;
}else{
return null;
}
}
}
}
],
tooltip: {
formatter: function() {
var s = '<b>Data</b> '+Highcharts.dateFormat('%H:%M:%S', this.x) + '<br><b>Temperatura</b> ' + this.y + '°C<br/>';
$.each(this.points, function(i, point) {
if(point.series.name != "Temperatura"){
s += '<b>' + point.series.name +'</b> : '+ point.y + '<br>';
}
});
return s;
},
shared: true,
backgroundColor: '#FCFFC5'
},
plotOptions: {
line : {
turboThreshold: 0,
},
series: {
animation: false,
marker: {
enabled: false
}
}
},
series: []
});
the problem occurs when run one (or more) zoom on the graphs , and on the y-axis the values are listed with more than two decimal places. I would like to limit to two the maximum number of decimal places.
I think i have to change this field (format)
yAxis: [
{
labels: {
format: '{value}°C',
},
but I do not know how.
Try to write the value as {value:.2f}, as proposed here: link
Is it possible to have Highcharts drilldown on multiple graphs that are sharing the same data when one graph is clicked?
As an example, I included a JSFiddle that uses the demo code (browser percentages).
http://jsfiddle.net/Pq6gb/
var gridster;
$(function(){
gridster = $(".gridster ul").gridster({
widget_base_dimensions: [150, 150],
widget_margins: [5, 5],
helper: 'clone',
resize: {
enabled: true,
stop: function(e, ui, $widget) {
for (var i = 0; i < Highcharts.charts.length; i++) {
Highcharts.charts[i].reflow();
}
}
}
}).data('gridster');
});
$(function () {
Highcharts.data({
csv: document.getElementById('tsv').innerHTML,
itemDelimiter: '\t',
parsed: function (columns) {
var brands = {},
brandsData = [],
versions = {},
drilldownSeries = [];
// Parse percentage strings
columns[1] = $.map(columns[1], function (value) {
if (value.indexOf('%') === value.length - 1) {
value = parseFloat(value);
}
return value;
});
$.each(columns[0], function (i, name) {
var brand,
version;
if (i > 0) {
// Remove special edition notes
name = name.split(' -')[0];
// Split into brand and version
version = name.match(/([0-9]+[\.0-9x]*)/);
if (version) {
version = version[0];
}
brand = name.replace(version, '');
// Create the main data
if (!brands[brand]) {
brands[brand] = columns[1][i];
} else {
brands[brand] += columns[1][i];
}
// Create the version data
if (version !== null) {
if (!versions[brand]) {
versions[brand] = [];
}
versions[brand].push(['v' + version, columns[1][i]]);
}
}
});
$.each(brands, function (name, y) {
brandsData.push({
name: name,
y: y,
drilldown: versions[name] ? name : null
});
});
$.each(versions, function (key, value) {
drilldownSeries.push({
name: key,
id: key,
data: value
});
});
// Create the chart
$('#container').highcharts({
chart: {
type: 'pie'
},
title: {
text: 'Browser market shares. November, 2013.'
},
subtitle: {
text: 'Click the slices to view versions. Source: netmarketshare.com.'
},
plotOptions: {
series: {
dataLabels: {
enabled: true,
format: '{point.name}: {point.y:.1f}%'
}
}
},
tooltip: {
headerFormat: '<span style="font-size:11px">{series.name}</span><br>',
pointFormat: '<span style="color:{point.color}">{point.name}</span>: <b>{point.y:.2f}%</b> of total<br/>'
},
series: [{
name: 'Brands',
colorByPoint: true,
data: brandsData
}],
drilldown: {
series: drilldownSeries
}
})
}
});
});
$(function () {
Highcharts.data({
csv: document.getElementById('tsv').innerHTML,
itemDelimiter: '\t',
parsed: function (columns) {
var brands = {},
brandsData = [],
versions = {},
drilldownSeries = [];
// Parse percentage strings
columns[1] = $.map(columns[1], function (value) {
if (value.indexOf('%') === value.length - 1) {
value = parseFloat(value);
}
return value;
});
$.each(columns[0], function (i, name) {
var brand,
version;
if (i > 0) {
// Remove special edition notes
name = name.split(' -')[0];
// Split into brand and version
version = name.match(/([0-9]+[\.0-9x]*)/);
if (version) {
version = version[0];
}
brand = name.replace(version, '');
// Create the main data
if (!brands[brand]) {
brands[brand] = columns[1][i];
} else {
brands[brand] += columns[1][i];
}
// Create the version data
if (version !== null) {
if (!versions[brand]) {
versions[brand] = [];
}
versions[brand].push(['v' + version, columns[1][i]]);
}
}
});
$.each(brands, function (name, y) {
brandsData.push({
name: name,
y: y,
drilldown: versions[name] ? name : null
});
});
$.each(versions, function (key, value) {
drilldownSeries.push({
name: key,
id: key,
data: value
});
});
// Create the chart
$('#container2').highcharts({
chart: {
type: 'column'
},
title: {
text: 'Browser market shares. November, 2013'
},
subtitle: {
text: 'Click the columns to view versions. Source: netmarketshare.com.'
},
xAxis: {
type: 'category'
},
yAxis: {
title: {
text: 'Total percent market share'
}
},
legend: {
enabled: false
},
plotOptions: {
series: {
borderWidth: 0,
dataLabels: {
enabled: true,
format: '{point.y:.1f}%'
}
}
},
tooltip: {
headerFormat: '<span style="font-size:11px">{series.name}</span><br>',
pointFormat: '<span style="color:{point.color}">{point.name}</span>: <b>{point.y:.2f}%</b> of total<br/>'
},
series: [{
name: 'Brands',
colorByPoint: true,
data: brandsData
}],
drilldown: {
series: drilldownSeries
}
})
}
});
});
There is a pie chart and a bar chart displaying the same data and can drilldown individually. I would like to click on any browser in the pie/bar chart and have both charts filter down to versions of that browser.
How would I go about doing this? Thanks.
Yes, it's possible. This is what you need to implement:
on drilldown event you can find respective point on a second chart and simple call 1point.doDrilldown()1
on drillup even in one chart, call on a second chart.drillUp()
Note: You need to be aware of infinite loop (for example drillUp() in one chart will call drillup event, which will drillUp() first chart again.. ) - just add some flag to call drillUp/doDrilldown only once per user click.