I'm encountering a weird issue that's probably my doing but I've tried everything I can e across.
I have one stacked column chart with eight different data sets. I have a select field with the titles of each data set.
const charts = [
{
"title": "Chart One",
"subtitle": "Subtitle One",
"source": "<p>Source One</p>\n",
"content": "<p>Content One</p>\n",
"series": [
{
"name": "Legend One",
"data": [0,0,0,0,0,0,0,0,0,0,null,0,0,0,0,null,0],
"stack": 0
},
{
"name": "Legend Two",
"data": [1085,1364,2398,2362,3954,6612,6388,8841,8397,6021,null,4962,7407,2825,2143,null,4823],
"stack": 0
}
]
},
{
"title": "Chart Two",
"subtitle": "Subtitle Two",
"source": "<p>Source Two</p>\n",
"content": "<p>Content Two</p>\n",
"series": [
{
"name": "Legend One",
"data": [380,608,469,285,634,1496,712,3059,1821,1049,null,916,2240,612,895,null,1064],
"stack": 0
},
{
"name": "Legend Two",
"data": [705,756,1928,2078,3320,5116,5676,5782,6576,4973,null,4046,5167,2212,1248,null,3759],
"stack": 0
}
]
},
{
"title": "Chart Three",
"subtitle": "Subtitle Three",
"source": "<p>Source Three</p>\n",
"content": "<p>Content Three</p>\n",
"series": [
{
"name": "Legend One",
"data": [648,932,1708,1326,2246,4646,4143,6732,6042,4222,null,3268,5723,1987,1501,null,3322],
"stack": 0
},
{
"name": "Legend Two",
"data": [438,432,690,1037,1708,1966,2244,2110,2355,1799,null,1694,1685,838,642,null,1501],
"stack": 0
}
]
},
{
"title": "Chart Four",
"subtitle": "Subtitle Four",
"source": "<p>Source Four</p>\n",
"content": "<p>Content Four</p>\n",
"series": [
{
"name": "Legend One",
"data": [380,608,469,285,634,1496,712,3118,2498,3567,null,1411,2687,698,1156,null,1479 ],
"stack": 0
},
{
"name": "Legend Two",
"data": [705,756,1928,2078,3320,5116,5676,5724,5899,2455,null,3551,4720,2126,987,null,3344],
"stack": 0
}
]
},
{
"title": "Chart Five",
"subtitle": "Subtitle Five",
"source": "<p>Source Five</p>\n",
"content": "<p>Content Five</p>\n",
"series": [
{
"name": "Legend One",
"data": [561,852,1362,2012,3404,5643,6195,8153,8158,5905,null,4502,6243,2646,1750,null,4305],
"stack": 0
},
{
"name": "Legend Two",
"data": [524,512,1036,350,550,969,193,689,240,117,null,460,1165,178,393,null,518],
"stack": 0
}
]
},
{
"title": "Chart Six",
"subtitle": "Subtitle Six",
"source": "<p>Source Six</p>\n",
"content": "<p>Content Six</p>\n",
"series": [
{
"name": "Legend One",
"data": [120,209,397,655,1115,2584,2944,3322,3075,2266,null,1751,2606,1032,740,null,1704],
"stack": 0
},
{
"name": "Legend Two",
"data": [965,1155,2000,1708,2840,4027,3443,5519,5323,3755,null,3211,4802,1793,1403,null,3118],
"stack": 0
}
]
},
{
"title": "Chart Seven",
"subtitle": "Subtitle Seven",
"source": "<p>Source Seven</p>\n",
"content": "<p>Content Seven</p>\n",
"series": [
{
"name": "Legend One",
"data": [294,494,391,800,1765,4227,5474,7212,7705,5836,null,3755,4640,2070,1463,null,3490],
"stack": 0
},
{
"name": "Legend Two",
"data": [791,870,2007,1563,2189,2385,914,1630,692,186,null,1207,2768,755,680,null,1333],
"stack": 0
}
]
},
{
"title": "Chart Eight",
"subtitle": "Subtitle Eight",
"source": "<p>Source Eight</p>\n",
"content": "<p>Content Eight</p>\n",
"series": [
{
"name": "Legend One",
"data": [486,741,1160,1825,3105,5205,6012,7553,7723,5780,null,4259,5754,2424,1596,null,4035],
"stack": 0
},
{
"name": "Legend Two",
"data": [599,623,1237,537,849,1407,376,1288,674,242,null,703,1654,401,547,null,787],
"stack": 0
}
]
}
]
When a user selects the chart they want to view, I then grab the data needed charts[selectedIndex].series and pass that to:
chartObj.update({
series: charts[selectedIndex].series
}, false );
chartObj.redraw();
This overall works and the chart is updated correctly, however, chart[0].series
gets updated with the last selected chart data. The chart array is getting modified for some odd reason. It only modifies the first chart in the array. For the life of me, I can't figure out why this is occurring. Any insight would be greatly appreciated.
I've also tried a for loop going through the chartObj series and matching it to the desired charts array item, and using .setData
with the 'data' but that had it's own issues. This did not modify the original array, however the chart would no longer update. I tried the same loop with .update as well.
Codepen with the error:
I'm encountering a weird issue that's probably my doing but I've tried everything I can e across.
I have one stacked column chart with eight different data sets. I have a select field with the titles of each data set.
const charts = [
{
"title": "Chart One",
"subtitle": "Subtitle One",
"source": "<p>Source One</p>\n",
"content": "<p>Content One</p>\n",
"series": [
{
"name": "Legend One",
"data": [0,0,0,0,0,0,0,0,0,0,null,0,0,0,0,null,0],
"stack": 0
},
{
"name": "Legend Two",
"data": [1085,1364,2398,2362,3954,6612,6388,8841,8397,6021,null,4962,7407,2825,2143,null,4823],
"stack": 0
}
]
},
{
"title": "Chart Two",
"subtitle": "Subtitle Two",
"source": "<p>Source Two</p>\n",
"content": "<p>Content Two</p>\n",
"series": [
{
"name": "Legend One",
"data": [380,608,469,285,634,1496,712,3059,1821,1049,null,916,2240,612,895,null,1064],
"stack": 0
},
{
"name": "Legend Two",
"data": [705,756,1928,2078,3320,5116,5676,5782,6576,4973,null,4046,5167,2212,1248,null,3759],
"stack": 0
}
]
},
{
"title": "Chart Three",
"subtitle": "Subtitle Three",
"source": "<p>Source Three</p>\n",
"content": "<p>Content Three</p>\n",
"series": [
{
"name": "Legend One",
"data": [648,932,1708,1326,2246,4646,4143,6732,6042,4222,null,3268,5723,1987,1501,null,3322],
"stack": 0
},
{
"name": "Legend Two",
"data": [438,432,690,1037,1708,1966,2244,2110,2355,1799,null,1694,1685,838,642,null,1501],
"stack": 0
}
]
},
{
"title": "Chart Four",
"subtitle": "Subtitle Four",
"source": "<p>Source Four</p>\n",
"content": "<p>Content Four</p>\n",
"series": [
{
"name": "Legend One",
"data": [380,608,469,285,634,1496,712,3118,2498,3567,null,1411,2687,698,1156,null,1479 ],
"stack": 0
},
{
"name": "Legend Two",
"data": [705,756,1928,2078,3320,5116,5676,5724,5899,2455,null,3551,4720,2126,987,null,3344],
"stack": 0
}
]
},
{
"title": "Chart Five",
"subtitle": "Subtitle Five",
"source": "<p>Source Five</p>\n",
"content": "<p>Content Five</p>\n",
"series": [
{
"name": "Legend One",
"data": [561,852,1362,2012,3404,5643,6195,8153,8158,5905,null,4502,6243,2646,1750,null,4305],
"stack": 0
},
{
"name": "Legend Two",
"data": [524,512,1036,350,550,969,193,689,240,117,null,460,1165,178,393,null,518],
"stack": 0
}
]
},
{
"title": "Chart Six",
"subtitle": "Subtitle Six",
"source": "<p>Source Six</p>\n",
"content": "<p>Content Six</p>\n",
"series": [
{
"name": "Legend One",
"data": [120,209,397,655,1115,2584,2944,3322,3075,2266,null,1751,2606,1032,740,null,1704],
"stack": 0
},
{
"name": "Legend Two",
"data": [965,1155,2000,1708,2840,4027,3443,5519,5323,3755,null,3211,4802,1793,1403,null,3118],
"stack": 0
}
]
},
{
"title": "Chart Seven",
"subtitle": "Subtitle Seven",
"source": "<p>Source Seven</p>\n",
"content": "<p>Content Seven</p>\n",
"series": [
{
"name": "Legend One",
"data": [294,494,391,800,1765,4227,5474,7212,7705,5836,null,3755,4640,2070,1463,null,3490],
"stack": 0
},
{
"name": "Legend Two",
"data": [791,870,2007,1563,2189,2385,914,1630,692,186,null,1207,2768,755,680,null,1333],
"stack": 0
}
]
},
{
"title": "Chart Eight",
"subtitle": "Subtitle Eight",
"source": "<p>Source Eight</p>\n",
"content": "<p>Content Eight</p>\n",
"series": [
{
"name": "Legend One",
"data": [486,741,1160,1825,3105,5205,6012,7553,7723,5780,null,4259,5754,2424,1596,null,4035],
"stack": 0
},
{
"name": "Legend Two",
"data": [599,623,1237,537,849,1407,376,1288,674,242,null,703,1654,401,547,null,787],
"stack": 0
}
]
}
]
When a user selects the chart they want to view, I then grab the data needed charts[selectedIndex].series and pass that to:
chartObj.update({
series: charts[selectedIndex].series
}, false );
chartObj.redraw();
This overall works and the chart is updated correctly, however, chart[0].series
gets updated with the last selected chart data. The chart array is getting modified for some odd reason. It only modifies the first chart in the array. For the life of me, I can't figure out why this is occurring. Any insight would be greatly appreciated.
I've also tried a for loop going through the chartObj series and matching it to the desired charts array item, and using .setData
with the 'data' but that had it's own issues. This did not modify the original array, however the chart would no longer update. I tried the same loop with .update as well.
Codepen with the error: https://codepen.io/rossberenson/pen/mdrWgPe
Share Improve this question edited Dec 23, 2020 at 18:21 Ross Berenson asked Dec 23, 2020 at 17:53 Ross BerensonRoss Berenson 3471 gold badge4 silver badges11 bronze badges 5-
Because you have set
series:charts[0].series
when you initialize Highchart, when you update Highchart it is settingcharts[0]
to the new series. If you instead use a separate array for display, Highchart will update that instead and leavecharts
untouched. soseries: active[0].series
and make an arrayconst active =[...first object from charts array to start]
– pilchard Commented Dec 23, 2020 at 18:52 -
@pilchard - Thank you for this. I think I understand. I updated codepen.io/rossberenson/pen/mdrWgPe. I added const active, duplicating the charts array. Then when highcharts is initialized, it's looking at active[0].series. All good there, but when I go to update via selection. The charts array is being modified again. I assume it's because I'm not setting the series to be something else. I tried to then do a similar idea for the update.
const selectedChartData = [...charts[selectedChart].series];
but still have the same issue. Hmm – Ross Berenson Commented Dec 23, 2020 at 19:15 -
I see that you spread the charts array into the new active array. This was a good thought, but unfortunately cloning the array this way doesn't clone the nested objects, so when you switch the
series
it still updates the nested array in the originalcharts
array. Instead, simply paste the entire first object in thecharts
array into the active array and then it works. (You could do this functionally, but you'll need to clone every level of each object nested insidecharts
). – pilchard Commented Dec 23, 2020 at 21:57 - If you're curious, see: What is the most efficient way to deep clone an object in JavaScript? if you'r curious. – pilchard Commented Dec 23, 2020 at 21:57
- @pilchard - Thanks for all of this. It's vert insightful, and I learned some new things. – Ross Berenson Commented Dec 24, 2020 at 2:18
2 Answers
Reset to default 4I dug a little deeper and found that the chart.update()
call was switching out the nested series
array but wasn't updating the entire chart object, more than that even cloning the series
array using map(o => ({...o}))
doesn't clone the nested data
arrays so they are still prone to mutation. (you could use map(o => ({...o, data: [...o.data]}))
but it's fragile if your series/data structure changes).
So... here is a quick snippet that stores the datasets in their own array and sets the Highchart.series
option to a separate active
object.
The active
object is initially assigned a cloned version of the first chart object using JSON
for deep cloning – see this question for deeper discussion of its shortings and better options What is the most efficient way to deep clone an object in JavaScript?
When the select change
event fires, the chart object at the newly selected index is cloned using the same method and assigned to the active
object.
Finally, chart.update()
is called pointing to the same active.series
as when the highchart class was instantiated.
const cloneSample = (sample) => {
// Crude JSON deep clone – see referenced question for discussion
return JSON.parse(JSON.stringify(sample));
}
let active = cloneSample(samples[0]);
const highchart = Highcharts.chart('container', {
chart: { type: 'bar' }, title: { text: active.title },
xAxis: { categories: ['Apples', 'Oranges', 'Pears', 'Grapes', 'Bananas'] },
yAxis: { min: 0, title: { text: 'Total fruit consumption' } }, legend: { reversed: false },
plotOptions: { series: { stacking: 'normal' } },
series: active.series
});
const select = document.querySelector('.select');
select.addEventListener('change', () => {
let
selected = select.value,
newSample = cloneSample(samples[selected]);
active = newSample;
highchart.update({
title: { text: active.title },
series: active.series,
});
});
<script src="https://code.highcharts./highcharts.js"></script>
<select class="select">
<option value="0">Sample One</option>
<option value="1">Sample Two</option>
<option value="2">Sample Three</option>
</select>
<div id="container"></div>
<script>
const samples = [
{
"title": "Sample One",
"series": [
{
name: 'John',
data: [5, 3, 4, 7, 2]
}, {
name: 'Jane',
data: [2, 2, 3, 2, 1]
}, {
name: 'Tara',
data: [3, 4, 4, 2, 5]
}
]
},
{
"title": "Sample Two",
"series": [
{
name: 'Donna',
data: [2, 1, 4, 6, 2]
}, {
name: 'Mark',
data: [1, 4, 3, 4, 1]
}, {
name: 'Tim',
data: [6, 4, 9, 3, 5]
}
]
},
{
"title": "Sample Three",
"series": [
{
name: 'Mara',
data: [3, 3, 1, 7, 2]
}, {
name: 'Tom',
data: [0, 1, 2, 4, 1]
}, {
name: 'Lara',
data: [3, 8, 5, 2, 5]
}
]
}
]
</script>
Currently there is some issue in HightChart it is not working properly when run old application it through an exception. I describe the error:
Highchart is not a constructor
at createChartchart ((index):48:1524)
at HTMLDocument. ((index):48:198)
I solved the error by this way
var mydata = renderer.Replace("new Highcharts.chart", "Highcharts.chart");
stringBuilder.Append(renderer);
I provide the plete sample code please visit this link.
HighChart New Update in Core