最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Highcharts .update modifying original data array - Stack Overflow

programmeradmin0浏览0评论

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 setting charts[0] to the new series. If you instead use a separate array for display, Highchart will update that instead and leave charts untouched. so series: active[0].series and make an array const 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 original charts array. Instead, simply paste the entire first object in the charts 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 inside charts). – 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
Add a ment  | 

2 Answers 2

Reset to default 4

I 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

发布评论

评论列表(0)

  1. 暂无评论