Vue uses zrenderjs to draw coordinate axes

Vue uses zrenderjs to draw coordinate axes

First introduce zrender.js
to draw y-axis, x-axis, and scatter points respectively
.
Idea: Define the point object, the x-axis object, and the y-axis object, all of which are introduced in the relative positioning object, and different methods can be used by judging the display on the app and pc.
The current realization: the y-axis 0 coordinate is always fixed, and the x-axis arc can be dragged to zoom in.
Used for: relative positioning map.
Insert picture description here
(Draw with zrender, the original coordinates are in the upper left corner, and the overall drawing is based on height.)

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>Demo</title>
    <script type="text/javascript" src="./dist/zrender.min.js"></script>
</head>

<body>
    <div id="main" style="width:80vw;height:80vh;padding: 10px;"></div>
    <script>
        //相对定位图中人员点
        class Point {
            //人员状态
            color = '#2196f3';
            //人员名称
            name = '';
            //人员高度
            height = 0;
            //人员距离
            distant = 0;
            //zrender实例
            zr = null;
            //Circle实例
            circle = null;
            //axisX实例
            axisX = null;
            //axisYX\实例
            axisY = null;
            //构造函数
            constructor(data) {
                let {
                    zr,
                    axisX,
                    axisY,
                    height,
                    distant,
                    name
                } = data;
                this.zr = zr; //zrender实例
                this.height = height;
                this.distant = distant;
                this.name = name;
                this.axisX = axisX;
                this.axisY = axisY;
                //绘制
                this.draw();
            }

            draw() {
                let coord = this.convertCoord();
                this.circle = new zrender.Circle({
                    style: {
                        fill: this.color,
                        text: `${this.name}`,
                        textFill: this.color,
                        textPosition: [0, 25]
                    },
                    shape: {
                        cx: coord.x,
                        cy: coord.y,
                        r: 10
                    }
                });
                this.zr.add(this.circle);
            }

            update() {
                this.draw();
            }

            /**
             * 根据人员高度和距离转换坐标
             */
            convertCoord() {
                const max = Math.max(...this.axisX.extent); //x轴的最大值
                const maxY = Math.max(...this.axisY.extent); //y轴的最大值
                const minY = Math.min(...this.axisY.extent); //y轴的最大值
                // let totalNumber = max / this.intervalCnt + Math.abs(min) / this.intervalCnt,
                //     intervalDis = this._height  / totalNumber,//坐标轴之间的间隔距离
                let r = (this.zr.getHeight() / 2 - this.axisX.textOffset) / Math.sin(this.axisX.angle), //计算弧线半径
                    intervalDis = (this.zr.getWidth() * this.axisX.scale) / max, //计算单位间隔
                    totalNumber = maxY  + Math.abs(minY) , //计算Y轴条数
                    intervalDisY = (this.zr.getHeight() - 20) * this.axisY.scale / totalNumber,//Y轴 坐标轴之间的间隔距离
                    cx = r * (1 - Math.cos(this.axisX.angle)) + this.axisX.offset, //计算初始x坐标
                    cy = (this.zr.getHeight() / 2 - this.axisX.textOffset), //计算初始y坐标
                    x = cx + this.distant * intervalDis, //计算x坐标
                    y = cy - this.height * intervalDisY; //计算y坐标
                    // console.log('intervalDisY',intervalDisY)
                    // console.log('计算初始y坐标',cy)
                    // console.log('计算初始x坐标',cx)
                    // console.log('计算x坐标',x)
                    // console.log('计算y坐标',y)
                //x坐标超出范围,控制在外面
                if (this.distant > max) x = intervalDis * (max + Math.random());
                return {
                    x,
                    y
                };
            }

        }

        //相对定位图X轴对象
        class AxisX {
            //坐标轴范围
            extent = [0, 35];
            //坐标轴宽度
            _width = 0;
            //坐标轴高度
            _height = 0;
            //坐标轴圆弧的角度(一半)
            angle = 0.5;
            //坐标轴间隔数
            intervalCnt = 5;
            //坐标轴间隔距离
            intervalDis = 10;
            //坐标轴的缩放比例
            scale = 1;
            //坐标偏移量
            offset = 0;
            //文字偏移距离
            textOffset = 10;
            //zrender实例
            zr = null;
            //构造函数
            constructor(zr) {
                this.zr = zr; //zrender实例
                this._height = zr.getHeight(); //设置坐标轴高度
                //绘制
                this.draw();
            }

            //绘制弧线
            draw() {
                const max = Math.max(...this.extent), //最大值
                    min = Math.min(...this.extent), //最小值
                    cy = this.zr.getHeight() / 2 - this.textOffset, //圆心纵坐标
                    r = cy / Math.sin(this.angle); //弧形半径
                this._width = this.zr.getWidth() * this.scale; //设置坐标轴宽度
                this.intervalCnt = Math.ceil(5 / this.scale); //设置坐标轴间隔
                let intervalDis = this._width / max, //坐标轴之间的间隔距离
                    chordHalf = r * Math.sin(this.angle), //弦长的一半
                    cx = this.offset - r * Math.cos(this.angle); //圆心横坐标
                // console.log("max", max);
                // console.log("min", min);
                // console.log("r", r);
                // console.log("cy", cy);
                // console.log("cx", cx);
                // console.log("chordHalfX", chordHalf* 2 );
                // console.log("intervalDis", intervalDis);
                // console.log("intervalCnt", this.intervalCnt);
                // console.log("_width", this._width);
                // console.log("angle", this.angle);
                // console.log("offset", this.offset);
                for (let i = 0; i <= max; i++) {
                    //每隔intervalCnt绘制一条弧线
                    if ((min + i) % this.intervalCnt !== 0 && i !== 0) continue;
                    //构造弧线
                    let arc = new zrender.Arc({
                        style: {
                            text: `${min + i} 米`, //文字内容
                            textPosition: [0, chordHalf * 2 + this.textOffset] //文字偏移距离
                        },
                        shape: {
                            cx: cx + intervalDis * i, //圆心横坐标
                            cy: cy, //圆心纵坐标
                            r: r, //半径
                            startAngle: -this.angle, //起始弧度
                            endAngle: this.angle //终止弧度
                        }
                    });
                    this.zr.add(arc);
                }
            }

            //更新图形
            update(data) {
                let {
                    offset,
                    scale
                } = data;
                if (offset) this.offset = offset; //更新偏移量
                if (scale) this.scale = scale; //更新缩放等级
                this.draw(); //绘制图形
            }
        }

        //相对定位图Y轴对象
        class AxisY {
            //坐标轴范围
            extent = [-40, 40];
            //坐标轴宽度
            _width = 0;
            //坐标轴高度
            _height = 0;
            //坐标轴圆弧的角度(一半)
            angle = 0;
            //坐标轴间隔数
            intervalCnt = 4;
            //坐标轴间隔距离
            intervalDis = 10;
            //坐标轴的缩放比例
            scale = 1;
            //坐标偏移量
            offset = 1;
            //文字偏移距离
            textOffset = 10;
            //zrender实例
            zr = null;
            //构造函数
            constructor(zr) {
                this.zr = zr; //zrender实例
                this._height = zr.getHeight(); //设置坐标轴高度
                //绘制
                this.draw();
            }

            //绘制直线
            draw() {
                const max = Math.max(...this.extent), //最大值
                      min = Math.min(...this.extent), //最小值
                      cy = this.zr.getHeight() / 2 - this.textOffset, //圆心纵坐标
                      r = cy / Math.sin(this.angle), //弧形半径
                      total = max + Math.abs(min);
                this._width = this.zr.getWidth() * this.scale; //设置坐标轴宽度
                this._height = (this.zr.getHeight() - 20) * this.scale; //设置坐标轴高度
                this.intervalCnt = Math.ceil(4 / this.scale); //设置坐标轴间隔
                let chordHalf = r * Math.sin(this.angle) * 2, //弦长的一半
                    // totalNumber = max / this.intervalCnt + Math.abs(min) / this.intervalCnt,
                    totalNumber = max + Math.abs(min),
                    intervalDis = this._height  / totalNumber,//坐标轴之间的间隔距离
                    x1 = 0,
                    y1 = 0,
                    y2 = 0,
                    x2 = this.zr.getWidth();
                // console.log("max", max);
                // console.log("min", min);
                // console.log("x1", x1);
                // console.log("y1", y1);
                // console.log("x2", x2);
                // console.log("y2", y2);
                // console.log("坐标轴之间的间隔距离", intervalDis);
                // console.log("设置坐标轴间隔", this.intervalCnt);
                // console.log("_width", this._width);
                // console.log("this._height", this._height);
                // console.log("chordHalf",chordHalf);
                // console.log("(total / (this.intervalCnt) + 1)",(total / (this.intervalCnt) + 1))
                for (let i = 0; i <= total; i++) {
                    if ((min + i) % this.intervalCnt !== 0 && i !== 0) continue;
                    console.log('min',min)
                    let arc = new zrender.Line({
                        style: {
                            text: `${-( min + i)} 米`, //文字内容
                            // text: `${ this.intervalCnt* i} 米`,
                            textPosition: [4, -10] //文字偏移距离
                        },
                        shape: {
                            x1:x1,
                            y1:y1 + intervalDis * i,
                            y2:y1 + intervalDis * i,
                            x2:x2
                        }
                    });
                    this.zr.add(arc);
                }
            }

            //更新图形
            update(data) {
                let {
                    offset,
                    scale
                } = data;
                if (offset) this.offset = offset; //更新偏移量
                if (scale) this.scale = scale; //更新缩放等级
                this.draw(); //绘制图形
            }
        }


        //相对定位图对象
        class XDDWChart {
            //zrender实例对象
            zr = null;
            //dom元素id
            eleId = '';
            //相对定位图X轴
            axisX = null;
            //相对定位图Y轴
            axisY = null;
            //坐标轴的缩放比例
            scale = 1;
            //坐标偏移量 (整体移动)
            offset = 0;
            //相对定位图中的点集合
            pointArr = [];
            //触碰开始时x坐标
            _touchStartX = 0;
            //触碰开始时y坐标
            _touchStartY = 0;
            //触碰开始时两指坐标距离
            _touchStartDis = 0;
            //临时偏移量
            _tempOffset = 0;
            //构造函数
            constructor(eleId) {
                //初始化zrender画布
                this.zr = zrender.init(document.getElementById(eleId));
                //设置dom元素id
                this.eleId = eleId;
                //相对定位图X轴实例
                this.axisX = new AxisX(this.zr);
                //相对定位图X轴实例
                this.axisY = new AxisY(this.zr);
                //添加鼠标、手势监听事件
                this.addEventListener();
            }

            //绘制图
            draw() {
                this.axisX.draw();
                this.axisY.draw();
            }

            //更新图
            update() {
                this.zr.clear();
                this.axisX.update({
                    offset: this.offset,
                    scale: this.scale
                });
                this.axisY.update({
                    offset: this.offset,
                    scale: this.scale
                });
                this.pointArr.forEach(v => {
                    v.update();
                })
            }

            //添加点
            addPoints(data) {
                data.forEach(v => {
                    let p = new Point({
                        ...v,
                        zr: this.zr,
                        axisX: this.axisX,
                        axisY: this.axisY
                    });
                    this.pointArr.push(p);
                });
            }

            //判断是否是PC端
            isPC() {
                let userAgentInfo = navigator.userAgent;
                let Agents = ["Android", "iPhone",
                    "SymbianOS", "Windows Phone",
                    "iPad", "iPod"
                ];
                let flag = true;
                for (let v = 0; v < Agents.length; v++) {
                    if (userAgentInfo.indexOf(Agents[v]) > 0) {
                        flag = false;
                        break;
                    }
                }
                return flag;
            }

            //添加事件监听
            addEventListener() {
                this.isPC() ? this.addPcEventListener() : this.addAppEventListener();
            }

            //添加PC端事件监听
            addPcEventListener() {
                document.getElementById(this.eleId).addEventListener('mousewheel', (e) => {
                    console.log("监听mousewheel", e);
                    let scaleTemp = this.scale;
                    if (e.wheelDelta > 0) {
                        scaleTemp += 0.1;
                    } else {
                        scaleTemp -= 0.1;
                    }
                    // console.log("scaleTemp", scaleTemp);
                    if (scaleTemp > 8 || scaleTemp < 1) return;
                    this.scale = Number(scaleTemp.toFixed(1));
                    console.log("scale", this.scale);
                    this.update();
                });
                // 行为过程:按下之后,移动,再抬起
                document.getElementById(this.eleId).addEventListener("mousedown", (eve) => {
                    console.log("mousedown", eve);
                    // 获取按下的坐标,在按下的事件对象身上
                    let e1 = eve || window.event;

                    this._touchStartX = e1.clientX;
                    this._touchStartY = e1.clientY;
                    this._tempOffset = this.offset;
                    // 因为移动事件在抬起的时候,被删除,所以提前起名
                    const move = (eve) => {
                            console.log("mousemove");
                            let e = eve || window.event;
                            // 计算元素要移动的真正的距离:为鼠标相对于页面的坐标减去按下时相对于元素的坐标
                            let l = e.clientX - this._touchStartX;
                            let t = e.clientY - this._touchStartY;
                            console.log("相对于元素的坐标 x,y:", l, t);
                            //TODO this._tempOffset + l

                            this.offset = this._tempOffset + l;
                            this.update();
                        }
                        // 为了防止移动过快,鼠标在某一瞬间离开元素,移动事件加给页面
                    document.addEventListener("mousemove", move);
                    // 抬起时,删除移动,删除抬起
                    document.addEventListener("mouseup", up)

                    function up() {
                        console.log("mouseup");
                        document.removeEventListener("mousemove", move)
                        document.removeEventListener("mouseup", up)
                    }
                })
            }

            //添加addAppEventListener()
            addAppEventListener() {
                document.getElementById(this.eleId).addEventListener('touchstart', (eve) => {
                    console.log("touchstart", eve)
                        // 获取按下的坐标,在按下的事件对象身上
                    let e1 = eve || window.event;
                    e1.preventDefault();
                    this._tempOffset = this.offset;
                    if (e1.touches.length >= 2) { //双指缩放
                        this._touchStartDis = this.getDistance(e1.touches[0], e1.touches[1]);
                        console.log("touchStart.dis", this._touchStartDis);
                    } else {
                        this._touchStartX = e1.touches[0].clientX;
                        this._touchStartY = e1.touches[0].clientY;
                    }
                    // 因为移动事件在抬起的时候,被删除,所以提前起名
                    const move = (eve) => {
                            // console.log("touchmove", eve);
                            let e = eve || window.event;
                            // e.preventDefault();
                            if (e.touches.length >= 2) { //双指缩放
                                let nowDis = this.getDistance(e.touches[0], e.touches[1]);
                                let scaleTemp = this.scale;
                                if (nowDis > this._touchStartDis) {
                                    scaleTemp += 0.1;
                                } else {
                                    scaleTemp -= 0.1;
                                }
                                if (scaleTemp > 8 || scaleTemp < 1) return;
                                this.scale = Number(scaleTemp.toFixed(1));
                                console.log("this.scale", this.scale);
                            } else {
                                // 计算元素要移动的真正的距离:为鼠标相对于页面的坐标减去按下时相对于元素的坐标
                                let l = e.touches[0].clientX - this._touchStartX;
                                let t = e.touches[0].clientY - this._touchStartY;
                                console.log("相对于元素的坐标 x,y:", l, t);
                                this.offset = this._tempOffset + l;
                            }
                            this.update();
                        }
                        // 为了防止移动过快,鼠标在某一瞬间离开元素,移动事件加给页面
                    document.addEventListener("touchmove", move);
                    // 抬起时,删除移动,删除抬起
                    document.addEventListener("touchend", up)

                    function up() {
                        console.log("mouseup");
                        document.removeEventListener("touchmove", move)
                        document.removeEventListener("touchend", up)
                    }
                })
            }

            //计算距离
            getDistance(p1, p2) {
                let x = p2.pageX - p1.pageX,
                    y = p2.pageY - p1.pageY;
                return Math.sqrt((x * x) + (y * y));
            }
        }

        let xddwChart = new XDDWChart('main');
        let points = [{
            height: 0,
            distant: 0,
            name: '张三'
        }, {
            height: 20,
            distant: 12.5,
            name: '李四'
        }, {
            height: 20,
            distant: 2,
            name: '王五'
        }, {
            height: -20,
            distant: 5,
            name: '赵柳'
        }, {
            height: -4,
            distant: 3,
            name: '丁一'
        }, {
            height: -8,
            distant: 5,
            name: '丁2'
        }, {
            height: -14,
            distant: 2.2,
            name: '丁3'
        }, {
            height: -8,
            distant: 2,
            name: '丁4'
        }, {
            height: -4,
            distant: 1,
            name: '丁5'
        }]
        xddwChart.addPoints(points);
    </script>
</body>

</html>

Guess you like

Origin blog.csdn.net/qq_45511353/article/details/113129937