Echarts--大数据展示

128 阅读3分钟

mock折线图Echarts数据

注意:必须要用reactive,不能用ref,否则数据量很大的时候会报错Maximum call stack size exceeded超出最大调用堆栈大小

import moment from 'moment'

const date = ref(moment().format('YYYY-MM-DD'))
const selectType = ref(3) //1表示时,2表示分,3表示秒
const setInterDelay = {
        3: {
            time: 1000,
            func: (val: string) => moment(val).format('HH:mm:ss'),
            name: '每秒',
            nowTime: moment().format('YYYY-MM-DD HH:mm:ss'),
            format: 'YYYY-MM-DD HH:mm:ss',
        },
        2: {
            time: 60 * 1000,
            func: (val: string) => moment(val).format('HH:mm'),
            name: '每分',
            nowTime: moment().format('YYYY-MM-DD HH:mm'),
            format: 'YYYY-MM-DD HH:mm',
        },
        1: {
            time: 60 * 60 * 1000,
            func: (val: string) => moment(val).format('HH'),
            name: '每时',
            nowTime: moment().format('YYYY-MM-DD HH'),
            format: 'YYYY-MM-DD HH',
        },
    }

// 看用哪种格式
const echartData = reactive({
    data: [],//格式[{label:'2024-05-20 09:09:09',value:'290.00'},...]
    xData: [],//格式['2024-05-20 09:09:09','2024-05-20 09:09:10',...]
    yData: [],//格式['290.00','190.00',...]
})

onMounted(() => {
    console.log('挂载了')
    setInterGetData()
})
onUnmounted(() => {
    console.log('卸载了')
    window.clearInterval(timer.value)
})

const setInterGetData = () => {
    window.clearInterval(timer.value)
    loading.value = true
    generateData() //初始化数据
    if (moment().format('YYYY-MM-DD') === date.value) {
        getItervalData() //定时数据
    }
}
// 过去时间不轮询
const getItervalData = () => {
    timer.value = window.setInterval(() => {
        setTimeout(() => {
            getPollingData()
        }, 0)
    }, setInterDelay[selectType.value].time)
}

// 手动mock返回的数据
function generateData() {
    //====mock时间begin=====
    const { time, func } = setInterDelay[selectType.value]
    let currentDay = date.value !== moment().format('YYYY-MM-DD'), //是否是当天时间
        startDate = date.value + ' 00:00:00', //开始时间
        endDate = currentDay ? date.value + ' 23:59:59' : new Date(), //结束时间
        countTimeCha = new Date(startDate).getTime() - new Date(endDate).getTime(), //开始时间和结束时间毫秒差
        countDelay = Math.abs(countTimeCha / time).toFixed(), //根据秒分时,确定x轴的时间长度
        count = currentDay ? Number(countDelay) : Number(countDelay) - 1 //当天时间取上一秒分时,过去的时间取全部
    // count = 86400 //当天时间取上一秒分时,过去的时间取全部
    console.log(count, 'count')
    //====mock时间end=====

    //====mock数据begin=====
    let timeDelay = +new Date(startDate)
    let baseValue = Math.random() * 1000
    let smallBaseValue = 0
    function next(idx: number) {
        smallBaseValue = idx % 30 === 0 ? Math.random() * 700 : smallBaseValue + Math.random() * 500 - 250
        baseValue += Math.random() * 20 - 10
        return Math.max(0, Math.round(baseValue + smallBaseValue) + 3000)
    }
    //====mock数据end=====

    const categoryData: any = []
    const valueData: any = []
    const echartXYData: any = []
    for (let i = 0; i < count; i++) {

        //===============
        categoryData.push(func(timeDelay))
        valueData.push(next(i).toFixed(2))

        //===============
      
        echartXYData.push({
            label: func(timeDelay),
            value: next(i).toFixed(2),
        })
        timeDelay += time
    }

    //===============
    echartData.xData = []
    echartData.xData = categoryData
    echartData.yData = []
    echartData.yData = valueData

    //===============
    echartData.data = []
    echartData.data = echartXYData
}

const getPollingData = async () => {
    const { format } = setInterDelay[selectType.value]
    const nowTime = moment().format(format)
    const paramsData = {
        date: nowTime,
        timeType: selectType.value,
        ...props.params,
    }

    const data: any = {
        xData: [nowTime],
        yData: [Math.random().toString().slice(2, 6)],
    }
    echartData.xData = echartData.xData.concat(data.xData)
    echartData.yData = echartData.yData.concat(data.yData)
    loading.value = false
}

image.png

image.png

大数据时的渲染优化

  1. dataZoom
dataZoom: [
    {
        type: 'inside', //内置型数据区域缩放组件
        show: true, //是否显示
        realtime: true, //拖动时,是否实时更新系列的视图
        start: 90,//伸缩条开始位置(1-100),可以随时更改
        end: 100,//伸缩条结束位置(1-100),可以随时更改
    },
    {
        type: 'slider', //滑动条型数据区域缩放组件
        show: true, //是否显示
        realtime: true, //拖动时,是否实时更新系列的视图
        start: 90,//伸缩条开始位置(1-100),可以随时更改
        end: 100,//伸缩条结束位置(1-100),可以随时更改
    },
],
const options = ref(props.option)

const draw = () => {
    if (chartInstance.value) {
        chartInstance.value.setOption(props.option, { notMerge: true })

        if (props.dataZoom)
            chartInstance.value.on('datazoom', (params: any) => {
                let start = 0,
                    end = 0
                start = params.batch ? params.batch[0].start : params.start
                end = params.batch ? params.batch[0].end : params.end
                options.value.dataZoom[0].start = start
                options.value.dataZoom[0].end = end
                options.value.dataZoom[1].start = start
                options.value.dataZoom[1].end = end
            })
    }
}

watch(props, () => {
    options.value = props.option
    draw()
})
  1. ECharts 有 提供 sampling 功能
series: {
    data: [],
    type: 'line',
    sampling: 'average', //降采样渲染
    ...
}
  1. 轮询获取数据
getListWaveformDat(count) {
    this.loading = true;//加载loading动画
    //获取波形图数据
    getListWaveformDat({
    deviceId: this.queryPointParams.deviceId,
    diId: this.diId,
    reportedOn: this.orgTime,
    keyName: this.dataAxis,
    num: this.pageNum,
    size: 10000,
    count: count ? count : '',
    }).then((res) => {
    if (res.length > 0) {
        this.noData = false//是否加载缺省值图片
        console.log(this.orgchart)
        if (this.orgchart) {
        this.orgchart.dispose();
        }
        this.oscillograph = res;
        let x = [];
        for (let i = 0; i < this.oscillograph.length; i++) {
        x[i] = this.oscillograph[i].count;
        }//处理X轴数据

        let y = [];
        for (let i = 0; i < this.oscillograph.length; i++) {
        y[this.oscillograph[i].count * 1 - 1] = this.oscillograph[i].value * 1
        }
        for (let i = 0; i < this.oscillographY.length; i++) {
        if (this.oscillographY[i] == undefined) {
            if (y[i]) {
            this.oscillographY[i] = y[i]
            }
        }
        }//处理Y轴数据
    
        console.log(this.oscillographY)
        this.pageNum = this.pageNum + 1;//轮询次数加1
        this.$nextTick(() => {
        this.orgDraw();//绘制图表

        })

        this.loading = false;//关闭加载loading
        this.getListWaveformDat(x[x.length - 1])//继续轮询
    

    }
    else {
        //如果加载的数据为空
        this.loading = false;
        console.log(this.orgchart)
        if (this.pageNum == 1) {
        //如果第一次轮询就为空,加载缺省图片
        this.noData = true;
        if (this.orgchart) {
            this.orgchart.dispose();//清除上一次加载的图表
        }
        
        this.pageNum = 1;//请求完所有数据之后初始化一下
        return
    }

    });
}

出现Maximum call stack size exceeded超出最大调用堆栈大小

原因:用的ref,5000+数据就会报错了

解决:用reactive代替ref

参考文献: