ECharts 自定义框选高亮

        截至目前,ECharts 自带的框选事件是brush,是只支持 scatter、bar、candlestick、parallel(平行坐标系) 这几个类型图的功能。

   

        所以,当我想要框选并自定义高亮的时候,尤其是在其它一些图上操作比如说折线图,brush就不能够满足我的需求。于是我重新自定义了一个框选动作,能够顶替这个brush。效果如下:

        思路:

        1. 高亮功能: 需要通过echarts的 visualMap 这个配置项来实现

        2. 框选功能: 先通过监听echarts的 mousedown + mousemove + mouseup 这三个动作组成一个框选的动作。然后通过动作事件获取到鼠标的位置,计算出框选的像素范围。再通过convertToPixel 方法依次获取坐标点的像素位置,判断数据点是否被选中。

        代码:

        Vue代码:

<template>
    <div>
        <div id="main" style="width: 1000px;height: 600px;"></div>
    </div>
</template>

<script>
import * as echarts from 'echarts';
import {addHandlersSelectionChart} from "@/util/ui-app";

export default {
    name: "EchartSpeed",
    data() {
        return {
            pointsTable: [],
            myChart: undefined
        }
    },
    mounted() {
        this.pointsTable = new Array(10).fill(0).map((d, i) => {
            return {
                X: i * 2,
                Y: Math.random() * 50 + 100,
                marked: Math.random() < 0.3
            }
        })
        this.paint()
    },
    methods: {
        paint() {
            this.myChart && this.myChart.dispose()
            this.myChart = echarts.init(document.getElementById('main'));

            let option = {
                animation: false,
                xAxis: {
                    type: 'value'
                },
                yAxis: {
                    type: 'value'
                },
                series: [{
                    data: this.pointsTable.map(d => [Number(d.X), Number(d.Y)]),
                    type: 'line',
                }]
            }

            let arr = this.pointsTable.map((d, i) => [Number(d.X), d.marked, i]).filter(d => d[1]);

            if (arr.length > 0) {
                let markarr = [],
                    st = -1,
                    begin = -1,
                    end = -1,
                    pieces = []
                arr.forEach((d, i) => {
                    if (begin === -1) {
                        st = d[2]
                        begin = d[0]
                    } else if (d[2] === st + 1) {
                        st = d[2]
                    } else {
                        markarr.push([begin, end])
                        begin = d[0]
                        st = d[2]
                    }
                    end = d[0]
                    if (i === arr.length - 1) {
                        markarr.push([begin, end])
                    }
                })

                markarr.forEach(d => {
                    pieces.push({min: d[0], max: d[1], color: 'blue'})
                })

                option.visualMap = {
                    type: 'piecewise',
                    pieces: pieces,
                    dimension: 0,
                    show: false,
                    inRange: {},
                    outOfRange: {
                        color: ['rgba(55,120,154,0.22)'],
                    }
                }
            }

            this.myChart.setOption(option);

            let state = {render: true};
            const setState = ({dragSelectActive}) => {
                state = {...state, render: dragSelectActive !== true};
            };

            addHandlersSelectionChart(this.myChart, (result) => {
                setState(result);

                const {offsetX, offsetY, width, height} = result;

                this.pointsTable.map(d => {
                    let p = this.myChart.convertToPixel('grid', [Number(d.X), Number(d.Y)])
                    d.marked = p[0] > offsetX && p[0] < offsetX + width && p[1] > offsetY && p[1] < offsetY + height;
                })

                !result.dragSelectActive && this.paint();
            });
        }
    }
}
</script>

<style>
.selection {
    visibility: hidden;
    pointer-events: none;
    position: absolute;
    border: 1px solid #677085;
    background-color: rgba(0, 90, 230, 0.17);
    width: 0;
    height: 0;
    top: 0;
    left: 0;
}
</style>

        ui-app.js代码:

const selectionDiv = document.createElement("div");
selectionDiv.className = "selection";

document.querySelector("body").appendChild(selectionDiv);

const clamp = (value, min, max) => Math.min(Math.max(min, value), max);

let selectionPoint = {x: 0, y: 0};
let meta = {ctrlKey: false, altKey: false};

export const addHandlersSelectionChart = (echart, callback) => {

    echart.getZr().on('mousedown', (e) => {
        callback({dragSelectActive: true});
        const {offsetX, offsetY, ctrlKey, altKey} = e;
        selectionPoint = {offsetX, offsetY};
        meta = {ctrlKey, altKey};
        selectionDiv.style.left = offsetX + "px";
        selectionDiv.style.top = offsetY + "px";
        selectionDiv.style.width = "0px";
        selectionDiv.style.height = "0px";

        echart.getZr().on("mousemove", mousemove);
        echart.getZr().on("mouseup", mouseup);
    });

    const mousemove = (e) => {
        const x = clamp(e.offsetX, 0, window.innerWidth - 2);
        const y = clamp(e.offsetY, 0, window.innerHeight - 2);
        const width = Math.abs(selectionPoint.offsetX - x);
        const height = Math.abs(selectionPoint.offsetY - y);
        selectionDiv.style.width = width + "px";
        selectionDiv.style.height = height + "px";
        selectionDiv.style.visibility = "visible";

        x < selectionPoint.offsetX && (selectionDiv.style.left = x + "px");
        y < selectionPoint.offsetY && (selectionDiv.style.top = y + "px");
    };

    const mouseup = (e) => {
        const {offsetX, offsetY} = e;
        const width = Math.abs(selectionPoint.offsetX - offsetX);
        const height = Math.abs(selectionPoint.offsetY - offsetY);
        selectionDiv.style.visibility = "hidden";

        const minSelectionSize = 0;
        echart.getZr().off("mousemove");
        echart.getZr().off("mouseup");
        if (width >= minSelectionSize && height >= minSelectionSize) {
            callback({
                offsetX: offsetX < selectionPoint.offsetX ? offsetX : selectionPoint.offsetX,
                offsetY: offsetY < selectionPoint.offsetY ? offsetY : selectionPoint.offsetY,
                width,
                height,
                ...meta
            });
        } else {
            callback({dragSelectActive: false});
        }

    };
};

支持原创!!
欢迎加入讨论!!!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值