echarts折线图实现矩形圈中的点可拖拽,圈外的点不可拖拽

原生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;
        }

        #ecDiv {
            width: 1400px;
            height: 600px;
            box-shadow: 0px 0px 10px #ccc;
            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>
  • 8
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,让我给你详细解释一下如何用Java实现绘图应用程序。 首先,你需要创建一个继承自JFrame类的主窗口,并设置标题和大小等基本属性。接着,在主窗口上添加一个绘图区域,可以使用JPanel或者Canvas等组件来实现。在绘图区域上,你需要添加鼠标事件监听器,如鼠标单击、鼠标拖拽等等,以便用户可以通过鼠标和键盘来绘图。 对于用户选择要画的图形,你可以使用下拉列表或者单选按钮等组件来提供选择。当用户选择图形后,你需要在绘图区域上根据用户选择的图形类型来绘制图形。你可以使用Java提供的Graphics2D类来绘制图形,它提供了许多方法,如drawLine()、drawRect()、drawOval()等等,可以用来绘制各种图形。 对于画笔颜色和画笔粗度的选择,你可以使用JColorChooser和JSlider等组件来提供选择。当用户选择颜色和粗度后,你需要在绘图区域上设置画笔的颜色和宽度,以便用户可以使用所选择的画笔来绘图。 最后,你需要添加保存和清除等功能,让用户可以保存绘制的图形或者清除绘图区域,以便重新开始绘图。 下面是一个简单的Java绘图应用程序的代码示例: ``` import java.awt.*; import java.awt.event.*; import javax.swing.*; public class DrawingApp extends JFrame { private JPanel drawingArea; private JComboBox<String> shapeComboBox; private JColorChooser colorChooser; private JSlider thicknessSlider; private Color currentColor; private int currentThickness; private int startX, startY, endX, endY; private boolean dragging; public DrawingApp() { setTitle("Drawing App"); setSize(800, 600); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); drawingArea = new JPanel(); drawingArea.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { startX = e.getX(); startY = e.getY(); dragging = true; } public void mouseReleased(MouseEvent e) { endX = e.getX(); endY = e.getY(); dragging = false; drawShape(); } }); drawingArea.addMouseMotionListener(new MouseAdapter() { public void mouseDragged(MouseEvent e) { endX = e.getX(); endY = e.getY(); drawShape(); } }); add(drawingArea, BorderLayout.CENTER); String[] shapes = {"Line", "Rectangle", "Oval"}; shapeComboBox = new JComboBox<>(shapes); shapeComboBox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { drawingArea.repaint(); } }); add(shapeComboBox, BorderLayout.NORTH); colorChooser = new JColorChooser(); colorChooser.getSelectionModel().addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { currentColor = colorChooser.getColor(); } }); add(colorChooser, BorderLayout.WEST); thicknessSlider = new JSlider(JSlider.HORIZONTAL, 1, 10, 1); thicknessSlider.setMajorTickSpacing(1); thicknessSlider.setPaintTicks(true); thicknessSlider.setSnapToTicks(true); thicknessSlider.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { currentThickness = thicknessSlider.getValue(); } }); add(thicknessSlider, BorderLayout.SOUTH); setVisible(true); } private void drawShape() { Graphics2D g2d = (Graphics2D) drawingArea.getGraphics(); g2d.setColor(currentColor); g2d.setStroke(new BasicStroke(currentThickness)); if (shapeComboBox.getSelectedItem().equals("Line")) { g2d.drawLine(startX, startY, endX, endY); } else if (shapeComboBox.getSelectedItem().equals("Rectangle")) { int x = Math.min(startX, endX); int y = Math.min(startY, endY); int w = Math.abs(startX - endX); int h = Math.abs(startY - endY); g2d.drawRect(x, y, w, h); } else if (shapeComboBox.getSelectedItem().equals("Oval")) { int x = Math.min(startX, endX); int y = Math.min(startY, endY); int w = Math.abs(startX - endX); int h = Math.abs(startY - endY); g2d.drawOval(x, y, w, h); } } public static void main(String[] args) { new DrawingApp(); } } ``` 在这个示例程序,我们创建了一个继承自JFrame类的主窗口,并在其上添加了一个绘图区域,一个下拉列表,一个颜色选择器,一个粗度滑块等组件。在绘图区域上,我们添加了鼠标事件监听器,以便用户可以通过鼠标和键盘来绘图。在下拉列表和颜色选择器上,我们添加了事件监听器,以便用户可以选择要画的图形和画笔颜色。在粗度滑块上,我们添加了事件监听器,以便用户可以选择画笔的粗度。最后,我们在drawShape()方法根据用户选择的图形类型来绘制图形。 这只是一个简单的示例程序,你可以根据自己的需求和兴趣来扩展和改进它。希望这个示例程序对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值