截至目前,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});
}
};
};
支持原创!!
欢迎加入讨论!!!