apache / echarts

Apache ECharts is a powerful, interactive charting and data visualization library for browser
https://echarts.apache.org
Apache License 2.0
60.82k stars 19.63k forks source link

[Bug] Line chart causing browser crash(out of memory) #19377

Open buctwp opened 11 months ago

buctwp commented 11 months ago

Version

5.4.3

Link to Minimal Reproduction

https://echarts.apache.org/examples/zh/editor.html?code=PYBwLglsB2AEC8skG8CwAoJSCG0IFttIYAuWAM2wBsBnAUwBpZIwq6y1Mskw6APMGQDkgbfjAX4qBj5UDRyoGylIQwzce_MAGUwATzYcKMNRABe7WAEYALLAC-irJYVcewYFUggdYAE4QA5t7ofhbD4IGiEre242P2gAEw47GyQ-AEFgmncNEGMhAGMiOm9gDw15WAAjYABXWOxigHFsNwpqeiYYomwyAG0AXXDE2A1UkIys4QA3akq6UqCQgBlsMroqHXIiwjBeANghZEmqacswy36HWHovOnTYLoGUWCollZIhExMABQAVAAYTUug2Hw2REElKmjGuyoEGgMzaHW6fQS5weT2Wqzen1-ACYAUDspJwZlstDYaV2mBOrckREsD0bNZ0BhyNUcsQ4DCIGAAKI5AAWtTANAAFABKWCcJRS2D8wUAeTKACsugADWUeMAAfQAJMgYTF-JYVX1EHR1UKAHScsDCmLAHKVYHQMAWvw8thOsAAIQ0AEkYsK1QKNTq9bFDSrRUxoJUqFQmJLpVKAO4QGJgPlkACsPx-tKT3D5dB8fMEsGxWaz92lllF1alAHoG7BAAH6gE_tQCGMYAZxMA37aAAqVAA6mgDtjetKc0K5VBwWh_URnoW-hgOXgKDQYWgdl1lG2DAYJvzJwgGXUKjM1nsi50MAAYWDYAAIh1hfgaN5xYmkyk0vM6NAANR_qOSAbquC7-BA1wWusHjctg_LCsKXJ0PgmrYkws58Kh4rwAAfBKQFKBA5CwM-r5dEhKHYhaaIrH0ACEiDVAa5AwnQMTvgRUoUahFoUtgFogJUNB8qR3jkbwlHUc8VA9FuBbStxVF8dRv7eBmsB4QAzLmsAAPywIpvEdAufJETa4rCEInE7tuUq1rutlKE2gAVSoAgAaAHfygCcpnwgAu8cO1kgTAFpfiERmUgJQkidBmwHnkVCPrwwpCHymb4PgJA0KEopyfJsCBdAwXDDQYX8Ww0BqXyGmwNpPx6QZEmaiYhVpCVJlmWKsCWQR9lMo5SBEcKGahSFNA_tADYAGy1fAiA_Dl8lDcV45Kqq5ozuGfBGvOORsLUYoEYtFrLZOa26hhW1gUuK4wIhEnzUodhAA

Steps to Reproduce

option = { animation: false, title: { text: '进出口压力', textStyle: { fontSize: 14 } }, tooltip: { trigger: 'axis' }, legend: {}, xAxis: { type: 'category', boundaryGap: false, data: [] }, yAxis: { type: 'value', axisLabel: { formatter: '{value}' } }, series: [ { label:'11PT01', name: '进口', type: 'line', data: [] }, { label:'11PT02', name: '出口', type: 'line', data: [] }, ] }

function initEcharts() { chartObj[chart_${index}] = echarts.init(document.getElementById(chart_${index}), null, { width: 500, height: 255 }) // 往对象里添加数据 chartObj[chart_${index}].setOption(option) }

//Loop call function setChartData(msg) { xAxisLen++ option.series.forEach((item_2, index_2) => { if (msg[item_2.label] != undefined) { item_2.data.push(msg[item_2.label]) item_2.data.length > 300 ? item_2.data.shift() : '' } })

        //动态修改x轴数据
        option.xAxis.data.push(formatLocalDate('hh:mm:ss'))
        option.xAxis.data.length > 300 ? item_1.xAxis.data.shift() : ''
      })

      if(this.xAxisLen/60 == 0)
        this.chartObj[`chart_${index}`].clear()
      this.chartObj[`chart_${index}`].setOption(item)
    },
  1. call initEcharts() to create the echarts
  2. Loop call setChartData() to set options
  3. when browser run 20 minutes, it will out of memory

Current Behavior

when browser run 20 minutes, it will out of memory

Expected Behavior

Memory usage remains stable

Environment

- OS:Windows 11
- Browser:Chrome
- Framework:JS

Any additional comments?

No response

buctwp commented 11 months ago

My program loops to add data to the option, but I set a maximum of 300 coordinate points. When there are more than 300 coordinate points, I will shift () the head coordinates from the X-axis and Y-axis data. Observation shows that when the number of data points reaches 300, the memory starts to soar. I suspect that the horizontal axis is constantly changing at this time, so Echarts has a problem rendering the graph.

buctwp commented 11 months ago

change this code if(this.xAxisLen/60 == 0) this.chartObj[chart_${index}].clear() to this.chartObj[chart_${index}].clear()

call clear() before each setOption seems to solve this problem

I have used it this way before, but in the past, charts seemed to shake, so I commented on this call.

Time1sMoney commented 10 months ago

我也出现了类似的问题,当我轮询更新数据的时候设置xAxis的max和数据时直接导致页面卡死,我现在都不知道问题到底出在哪里。

lstoryc commented 8 months ago

有办法监测这种崩溃么?

xela92 commented 1 month ago

Hi, is there any update about this? I think I have the same issue.

I created a simple chart with some random generated data, if I put more than 250 points and start moving around the chart: after some time (few seconds usually) the Chrome tab crashes with Error 5 (out of memory). If I lower them below 250, it seems to work fine (I don't know if it's only a matter of time before it crashes, though)

The issue doesn't exist with other browsers (tried Safari and Firefox): I managed to have ~2000 points without any hassle.

Here is the test config I used (copied from an example and slightly changed):

    let series_array = []
   // change 250 with an higher value leads to crash while painting tooltips (browsing the data)
    for (let i = 1; i < 250; i++) {
      let data = [1, 2, 3, 4, 5, 6, 7].map(function (x) {
        return x * Math.random()
      })

      let serie = {
        name: 'Serie' + i,
        type: 'line',
        data: data,
      }
      series_array.push(serie)
    }

  // Chart options

  let option = {
    title: {
      text: 'Line',
    },
    tooltip: {
      trigger: 'axis',
    },
    legend: {
      data: ['Email', 'Union Ads', 'Video Ads', 'Direct', 'Search Engine'],
    },
    grid: {
      left: '3%',
      right: '4%',
      bottom: '3%',
      containLabel: true,
    },
    toolbox: {
      feature: {
        saveAsImage: {},
      },
    },
    xAxis: {
      type: 'category',
      data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
    },
    yAxis: {
      type: 'value',
    },
    dataZoom: [
      {
        type: 'inside',
        start: 0,
        end: 100,
      },
      {
        start: 0,
        end: 100,
      },
    ],
    series: series,
  }

Any help would be very appreciated!

Thanks

xela92 commented 4 weeks ago

It seems I may have a workaround.

I tried to fully replace the tooltip with a templated string with some html inside, like this:

options: {
[...],
tooltip: {
   trigger: 'axis',
   axisPointer: {
            type: 'cross',
   },
   formatter: (params) => `
             <div><i>${moment(params[0].axisValue).format('ddd YYYY-MM-DD HH:mm')}</i></div>
             <div class="mt-[10px]">
             ${params
               .map(
                 (series) =>
                   `
                  <div class="flex gap-[5px] items-center mb-[5px]">
                      <svg width="20" height="20">
                          <circle cx="10" cy="10" r="5" fill="${series.color}" />  
                      </svg>
                      ${series.seriesName}: <b>${series.data}</b></text>
                  </div>
                  `,
               )
               .join('\n')}
              </div>`
   }

and I found out my example now works with Google Chrome without crashing.

Without this workaround, with the chart rendering approx 1500-2000 items, moving between the items would lead to crash after seconds; now it seems I'm unable to make it crash again.

That would mean that the issue is in the way the internal tooltip is managed, maybe some kind of caching strategy?

Hope it helps!