原生HTML + JavaScript版本
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>曲线形式的统计图示例</title><script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/4.9.0-rc.1/echarts.min.js"></script><!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/4.2.1/echarts.min.js"></script> --><style>* {margin: 0;padding: 0;}width: 1400px;height: 600px;box-shadow: 0px 0px 10px margin: 10px auto;}</style>
</head><body><div id="ecDiv"></div><button id="buttonid">保存数据</button>
</body><script type="text/javascript">function deepClone(obj) {if (obj === null || typeof obj !== 'object') {return obj; // 如果是原始值或函数,直接返回}let clone;if (Array.isArray(obj)) {clone = []; // 如果是数组,创建一个空数组for (let i = 0; i < obj.length; i++) {clone[i] = deepClone(obj[i]); // 递归深拷贝数组的每个元素}} else {clone = {}; // 如果是对象,创建一个空对象for (let key in obj) {if (obj.hasOwnProperty(key)) {clone[key] = deepClone(obj[key]); // 递归深拷贝对象的每个属性}}}return clone; // 返回深拷贝后的对象或数组}let color = ['#0071db', '#ff4868', 'yellow', 'green']let xdata = ["2024-07-10 00:00:00","2024-07-10 00:15:00","2024-07-10 00:30:00","2024-07-10 00:45:00","2024-07-10 01:00:00","2024-07-10 01:15:00","2024-07-10 01:30:00","2024-07-10 01:45:00","2024-07-10 02:00:00","2024-07-10 02:15:00",]const data = [{name: '预测功率',data: [1.415,2.685,4.237,5.993,7.869,9.818,12.677,16.624,20.0,20.0,]},{name: '手动修正',data: [1.415,2.685,4.237,5.993,7.869,9.818,12.677,16.624,20.0,20.0,]},{name: '置信上限',data: [1.698,3.222,5.085,7.191,9.443,11.782,15.213,19.949,24.0,24.0,]},{name: '置信下限',data: [1.132,2.148,3.39,4.794,6.296,7.854,10.142,13.299,16.0,16.0,]}]const lineStyle = {type: 'scatter',smooth: true,coordinateSystem: 'cartesian2d'}let batchSelected = [];const computedSeries = (Data, dif = 0) => {let selected = batchSelected;let items = [];Data.map((item, key) => {let point = {name: item.name,data: item.data.map((val, i) => {let dataValue = {value: val,symbolSize: 1,}return dataValue}),...lineStyle}items.push(point);})selected.map((item) => {let seriesIndex = item.seriesIndex;let findItem = items.find((v, k) => {if (item.seriesIndex === k) {return v;}});findItem && findItem.data.map((val, key) => {if (item.dataIndex.includes(key) && seriesIndex === 1) {val['symbolSize'] = 10;val['value'] = val.value + dif;}})})let lines = items.map((v, k) => {let itemData = v.data.map((v) => v.value);return {z: 1,type: 'line',name: v.name,data: itemData}})items.push(...lines)return items;}const echartDataSetData = (Data, dif = 0) => {if (dif == 0) return;let selected = batchSelected;selected.map((item) => {let seriesIndex = item.seriesIndex;let Dataitem = Data[seriesIndex];Dataitem && Dataitem.data.map((val, key) => {if (item.dataIndex.includes(key) && seriesIndex === 1) {Dataitem.data[key] = val + dif;}})})}let onmousedownY = 0;let oldDif = 0;const seriesDataToGraphic = (series) => {let dom = document.getElementById('ecDiv');let myChart = echarts.getInstanceByDom(dom);let graphic = [];series.map((item, sindex) => {if (item.type === 'scatter') {item.data.map((dt, tk) => {//! 等于10 标识选中if (dt.symbolSize && dt.symbolSize === 10) {let dataIndex = tk;let position = myChart.convertToPixel({ seriesIndex: sindex }, [dataIndex, dt.value]);let graphicItem = {type: 'circle',position: position,shape: {r: 5},invisible: true,draggable: true,onmousedown: echarts.util.curry((e) => {onmousedownY = e.offsetY;// myChart.dispatchAction({// type: 'restore'// })myChart.dispatchAction({type: 'takeGlobalCursor',key: null,})myChart.dispatchAction({type: 'brush',areas: []})}),ondrag: echarts.util.curry((dataI, e) => {let onmousedownYToValue = myChart.convertFromPixel({ seriesIndex: sindex }, [dataI, onmousedownY])[1];let ondragYToValue = myChart.convertFromPixel({ seriesIndex: sindex }, [dataI, e.offsetY])[1];let dif = onmousedownYToValue - ondragYToValue;let seriesData = computedSeries(data, -dif);let graphics = seriesDataToGraphic(seriesData);myChart.setOption({series: seriesData,graphic: graphics})oldDif = dif;}, dataIndex),ondragend: echarts.util.curry(() => {echartDataSetData(data, -oldDif);setSelectTitle(batchSelected)}, dataIndex),z: 100,}graphic.push(graphicItem);}})};})return graphic;}const setSelectTitle = (selected) => {let dom = document.getElementById('ecDiv');let myChart = echarts.getInstanceByDom(dom);let title = ''selected.map((item) => {if (!item.dataIndex.length) {return;}let seriesName = item.seriesName;let dataIndexList = item.dataIndex.map((i) => {return `{x|${xdata[i]}数值:${data[item.seriesIndex].data[i]}}\n`})let line = `{name|${seriesName}}${dataIndexList}`;title += '\n' + line;})// myChart.setOption({// title: {// text: '已选中:\n' + title,// right: 20,// top: 40,// textStyle: {// rich: {// name: {// color: '#333'// },// x: {// color: 'red'// }// }// }// }// })}const initEchart = () => {let dom = document.getElementById('ecDiv');let myChart = echarts.init(dom);let dataIndexs = [];let seriesIndexs = [];let series = computedSeries(data, []);let option = {color,xAxis: [{type: 'category',data: xdata}],yAxis: [{type: 'value'}],grid: {width: "80%",containLabel: true,left: 30,top: 50,right: 30,bottom: 20},legend: {show: true,data: data.map((v) => v.name)},brush: {xAxisIndex: 'all',throttleType: 'debounce',transformable: false,removeOnClick: true,brushMode: 'single',throttleDelay: 0,brushStyle: {borderWidth: 1,color: 'rgba(120,140,180,0.1)',borderColor: 'rgba(120,140,180,0.1)'},inBrush: {symbolSize: 10},outOfBrush: {colorAlpha: 1,opacity: 1},},animation: false,series}myChart.setOption(option);myChart.on('brushselected', (params) => {if (!params.batch[0].areas.length) {return;};let batch = deepClone(params.batch[0]);let selected = batch.selected;batchSelected = selected;let seriesData = computedSeries(data);let graphics = seriesDataToGraphic(seriesData);myChart.setOption({series: seriesData,graphic: graphics})setSelectTitle(selected);})// ! 点击取消 取消选中节点myChart.on('brush', (params) => {if (params?.command === 'clear') {batchSelected.length = 0;let seriesData = computedSeries(data);let graphics = seriesDataToGraphic(seriesData);myChart.setOption({series: seriesData,graphic: graphics})setSelectTitle([]);}})}const handleCli = () => {console.log("1123", data)setSelectTitle([]);}document.querySelector("#buttonid").onclick = handleCli;initEchart();
</script></html>
</html>