zoukankan      html  css  js  c++  java
  • highchart和ecahrt折线图性能对比

    https://www.cnblogs.com/lsjwq/p/11077281.html

    之前看到一篇比较性能的博文,我也稍微试了下,觉得差距没这么大

    46055条数据,10条曲线,也就是不到50W个数据点

    线条宽度都为1,不显示点形状,以获得较高性能

    echart v4.0   highchart v8.0

    测试过程不算严谨,仅供参考

    1,echart 

    页面进程内存占用939M

    js vm: 760M

    svg渲染  978M :

    js vm:776M

     在大量数据下,svg不会少占内存,而且在数据量密集时会更卡,几乎无法动态,canvas还能勉强缩放,两秒刷一帧,随着数据放大逐渐流畅

    2,highchart

    进程占用:343M  低很多

    js vm:223M

     

    不勾选数字较大的称重后,数据极为夸张 

     流畅度不高,而且由于放大时没有动画,比较讨巧,也要好几秒才有相应,随着数据放大较为流畅

    总体来说,highchart虽然是svg但是比echart的svg好很多,比echart的canvas性能也更好一些,主要是内存占用较小,在流畅度上由于操作和动画机制不同,不能直接对比,但是并没有感觉highchart比echart好很多

    浏览器的快捷方式加上这样的参数,可以提升一定的内存, --args --js-flags="--max_old_space_size=4096",不过实际最高也就2g多一点吧,v8引擎的限制,设置的再高也没用,所以echart我还没开成4个过,highchart占用内存小,一个界面要4个chart同步操作的话可能只能用highchart了。

    建议在实际使用时增加时间范围选择和数据间隔时间来减少数据量,否则几乎撑不住。


    做为对比,wpf下我用的chart控件可以显示4个甚至8个这样的chart同步操作,缩放非常流畅,4个chart内存占用才1G

    一些使用方法,我这种类给每个我用的chart都做了,C#的用了3个chart了。

    private static ToLower(str: string): string {
            let allsmallList = ['dopv', 'phpv'];
            for (let index = 0; index < allsmallList.length; index++) {
                const s = allsmallList[index];
                if (str.toLowerCase() == s)
                    return s;
            }
            //全大写的字母变成全小写,和后台统一改
            // var rt = /^[A-Z]+$/;
            // if (rt.test(str.replace(str[0], str[0].toUpperCase()))) {
            //     return str.toLowerCase();
            // }
    
            let str2 = str.replace(str[0], str[0].toLowerCase());
            return str2;
        }
    
        public static AddAllLineSeries(chartOption: any, batchDatas: Array<BatchData>, lineCodes: string[], lineProperties: Array<lineProperty>) {
            lineCodes.forEach(linecode => {
                linecode = echartLineSeriesHelper.ToLower(linecode);
                echartLineSeriesHelper.AddLineSeries(chartOption, batchDatas, linecode, lineProperties);
            });
        }
    
        public static AddLineSeries(chartOption: any, batchDatas: Array<BatchData>, lineCode: string, lineProperties: Array<lineProperty>) {
    
            let datas: Array<LineSeriesData>;
            let lineprop = lineProperties.firstOrDefault(lp => lp.lineCode == lineCode);
            if (lineprop) {
                if (lineprop.lineUnit == '%') {
                    datas = batchDatas.map(d => new LineSeriesData(lineprop.lineName, d.recordTime, d[lineCode] * 100));
                }
                else {
    
                    datas = batchDatas.map(d => new LineSeriesData(lineprop.lineName, d.recordTime, d[lineCode]));
                }
                echartLineSeriesHelper.AddLineSeriesInner(chartOption, datas, lineprop, 'online');
    
            }
        }
    
        public static AppendBatchDataToSeries(chartOption: any, batchData: BatchData, lineProperties: Array<lineProperty>) {
            let series: LineSeries[] = chartOption.series;
            lineProperties.forEach(lineprop => {
                series.forEach(ser => {
                    if (ser.name == lineprop.lineName) {
                        let linecode = echartLineSeriesHelper.ToLower(lineprop.lineCode);
                        ser.data.push(new LineSeriesData(ser.name, new Date(batchData.recordTime), batchData[linecode]));
                        if (ser.data.length > 10000) {
                            ser.data.shift();
                        }
                    }
                });
            });
        }
    
        public static AppendBatchDatasToSeries(chartOption: any, batchDatas: BatchData[], lineProperties: Array<lineProperty>) {
            let series: LineSeries[] = chartOption.series;
            lineProperties.forEach(lineprop => {
                series.forEach(ser => {
                    if (ser.name == lineprop.lineName) {
                        let linecode = echartLineSeriesHelper.ToLower(lineprop.lineCode);
                        batchDatas.forEach(batchData => {
                            ser.data.push(new LineSeriesData(ser.name, new Date(batchData.recordTime), batchData[linecode]));
                        });
                    }
                });
            });
        }
    
        public static InitBatchDataSeries(chartOption: any, lineProperties: Array<lineProperty>) {
            lineProperties.forEach(lineprop => {
                echartLineSeriesHelper.AddLineSeriesInner(chartOption, [], lineprop, 'online');
            });
        }
    
        private static AddLineSeriesInner(chartOption: any, datas: LineSeriesData[], lineProperty: lineProperty, dataType: string) {
            let lineSeries: LineSeries = {
                name: '',
                data: [],
                type: 'line',
                roam: true,
                showSymbol: false,
                lineStyle: {
                    normal: {
                        color: ''
                    },
                    1
                },
                dataType: 'online'
            };
    
            lineSeries.name = lineProperty.lineName;
            lineSeries.data = datas;
    
            let color: string
            if (lineProperty.lineColor.startsWith('#')) {
                color = '#' + lineProperty.lineColor.substr(3, 6);
            }
            else {
                color = lineProperty.lineColor;
            }
    
            lineSeries.lineStyle.normal.color = color;
            chartOption.color.push(color);
            chartOption.series.push(lineSeries);
        }
    echart加载数据辅助类
    private static ToLower(str: string): string {
            let allsmallList = ['dopv', 'phpv'];
            for (let index = 0; index < allsmallList.length; index++) {
                const s = allsmallList[index];
                if (str.toLowerCase() == s)
                    return s;
            }
            //全大写的字母变成全小写,和后台统一改
            // var rt = /^[A-Z]+$/;
            // if (rt.test(str.replace(str[0], str[0].toUpperCase()))) {
            //     return str.toLowerCase();
            // }
    
            let str2 = str.replace(str[0], str[0].toLowerCase());
            return str2;
        }
    
        public static AddAllLineSeries(chartOption: any, batchDatas: Array<BatchData>, lineCodes: string[], lineProperties: Array<lineProperty>) {
            lineCodes.forEach(linecode => {
                linecode = highchartLineSeriesHelper.ToLower(linecode);
                highchartLineSeriesHelper.AddLineSeries(chartOption, batchDatas, linecode, lineProperties);
            });
        }
    
        public static AddLineSeries(chartOption: any, batchDatas: Array<BatchData>, lineCode: string, lineProperties: Array<lineProperty>) {
    
            let datas: Array<HighChartLineSeriesData>;
            let lineprop = lineProperties.firstOrDefault(lp => lp.lineCode == lineCode);
            if (lineprop) {
                if (lineprop.lineUnit == '%') {
                    datas = batchDatas.map(d => new HighChartLineSeriesData(lineprop.lineName, d.recordTime, d[lineCode] * 100));
                }
                else {
    
                    datas = batchDatas.map(d => new HighChartLineSeriesData(lineprop.lineName, d.recordTime, d[lineCode]));
                }
                highchartLineSeriesHelper.AddLineSeriesInner(chartOption, datas, lineprop, 'online');
    
            }
        }
    
        public static AppendBatchDataToSeries(chartOption: any, batchData: BatchData, lineProperties: Array<lineProperty>) {
            let series: HighChartLineSeries[] = chartOption.series;
            lineProperties.forEach(lineprop => {
                series.forEach(ser => {
                    if (ser.name == lineprop.lineName) {
                        let linecode = highchartLineSeriesHelper.ToLower(lineprop.lineCode);
                        ser.data.push(new HighChartLineSeriesData(ser.name, new Date(batchData.recordTime), batchData[linecode]));
                        if (ser.data.length > 10000) {
                            ser.data.shift();
                        }
                    }
                });
            });
        }
    
        public static AppendBatchDatasToSeries(chartOption: any, batchDatas: BatchData[], lineProperties: Array<lineProperty>) {
            let series: HighChartLineSeries[] = chartOption.series;
            lineProperties.forEach(lineprop => {
                series.forEach(ser => {
                    if (ser.name == lineprop.lineName) {
                        let linecode = highchartLineSeriesHelper.ToLower(lineprop.lineCode);
                        batchDatas.forEach(batchData => {
                            ser.data.push(new HighChartLineSeriesData(ser.name, new Date(batchData.recordTime), batchData[linecode]));
                        });
                    }
                });
            });
        }
    
        public static InitBatchDataSeries(chartOption: any, lineProperties: Array<lineProperty>) {
            lineProperties.forEach(lineprop => {
                highchartLineSeriesHelper.AddLineSeriesInner(chartOption, [], lineprop, 'online');
            });
        }
    
        private static AddLineSeriesInner(chartOption: any, datas: HighChartLineSeriesData[], lineProperty: lineProperty, dataType: string) {
            let lineSeries: HighChartLineSeries = {
                name: '',
                data: [],
                type: 'line',
                dataType: 'online',
                lineWidth: 1,
                color:'',
                marker:{enabled:false}
            };
    
            lineSeries.name = lineProperty.lineName;
            lineSeries.data = datas;
    
            let color: string
            if (lineProperty.lineColor.startsWith('#')) {
                color = '#' + lineProperty.lineColor.substr(3, 6);
            }
            else {
                color = lineProperty.lineColor;
            }
    
            lineSeries.color = color;
            //chartOption.color.push(color);
            chartOption.series.push(lineSeries);
        }
    highchart数据加载辅助类
    {
          title: {
            text: ""
          },
          //renderer:'svg',
          color:[],
          legend: { data: [] },
          tooltip: {
            trigger: "axis",
            formatter: function(params: LineSeriesData[]) {
              let tootip = "";
              params.slice(0, 6).forEach(param => {
                tootip += param.name + " : " + param.value[1] + "<br/>";
              });
    
              return tootip;
            },
            axisPointer: {
              animation: false
            }
          },
          dataZoom: [
           {
              show: true,
              realtime: true,
              start: 65,
              end: 85
            },
            {
              type: "inside",
              show: true,
              realtime: true,
              start: 65,
              end: 85
            }
          ],
          xAxis: {
            type: "time",
            splitLine: {
              show: true
            }
          },
          yAxis: [
            {
              type: "value",
              splitLine: {
                show: true
              }
            }
          ],
          series: [],
          animation: false
        }
    echart options
    {
          plotOptions: {
            series: {
              turboThreshold: 1000000
            },
            radius: 0
          },
          title: {
            text: ""
          },
          chart: {
            zoomType: "x"
          },
          boost: {
            useGPUTranslations: true
          },
          color: [],
          legend: { data: [] },
    
          xAxis: {
            type: "datetime"
          },
          yAxis: [
            {
              type: "linear"
            }
          ],
          series: []
        }
    highchart option

    最后两个使用参数

     PS:echart使用了echart-vue,不过不用vue组件直接用echart内存也差不多,highchart的vue组件使用失败,只能用div id初始化

            不要尝试用vue router路由去切换这种数据量的chart了,虽然组件会保持数据,但是把DOM重新绘制出来还是很慢的,我多个tab时都是用v-show切换的

    再PS: 这也就是我不依赖electron做桌面端的原因之一,web端性能限制和内存限制,然后第三方c++组件也不方便调用

    补充,我发现lightningjs用webgl绘制的,性能好很多

  • 相关阅读:
    Android Facebook分享功能实现
    Facebook KeyHash生成方法
    Android 版 Facebook 登录
    在Android App中集成Google登录
    Android 应用程序集成FaceBook 登录及二次封装
    Android Facebook和Twitter登录和分享完整版
    android开发之自定义圆形ImagView
    Okhttp、Volley和Gson的简单介绍和配合使用
    Android并发编程
    重要的ui组件——Behavior
  • 原文地址:https://www.cnblogs.com/gxrsprite/p/12160032.html
Copyright © 2011-2022 走看看