html文件中实现svg图的绘制

该篇文章描述了一个HTML页面中通过JavaScript实现的SVG图形绘制功能,包括椭圆、矩形(圆角)、直线、折线、铅笔和等腰三角形的绘制,以及键盘控制的圆角和尺寸调整。
摘要由CSDN通过智能技术生成
  • 点击对应按钮可生成对应的图形
  • 按shift键可生成各图形对应的特殊图形
  • 此文件目前有:圆形,(圆角)矩形,直线,折线,铅笔,等腰三角形

此svg绘制功能是在一个html文件中实现,并未对函数进行封装

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>绘制svg图</title>
    <style>
        #svgCanvas {
            border: 1px solid #000;
        }

        .symble {
            background-color: rgb(71, 171, 221);
            color: white;
            padding: 1px
        }

        .myButton:hover {
            background-color: #069b4c;
            color: white;
        }
    </style>
</head>

<body>
    <button id="chooseTool" onclick="cancleChoose()" class="symble">选择工具</button>
    <button class="myButton" onclick="getEllipise()">圆形工具</button>
    <button class="myButton" onclick="getRectangle(false)">矩形工具</button>
    <button class="myButton" onclick="getRectangle(true)">圆角矩形工具</button>
    <button class="myButton" onclick="getLine()">直线工具</button>
    <button class="myButton" onclick="getPolyline()">折线工具</button>
    <button class="myButton" onclick="getPencile()">铅笔工具</button>
    <button class="myButton" onclick="getISOStriangle()">等腰三角形工具</button>
    
    <br>
  
    <svg id="svgCanvas" width="800" height="600">
    </svg>
    <script>
        const svg = document.getElementById("svgCanvas");
        let isDrawing = false;//是否选中绘制工具
        let newPath = "";//路径标签
        let isShiftPressed = false; //是否按下了shift键

        // 以数字或字母枚举,暂定 1:矩形,2:圆形,3:直线,4:折线,5:铅笔,6:等腰三角形工具
        let selectedShape; //选中的形状
        // *********************************************************
        let click_coordinateX = null; //开始绘制ellipse的起点
        let click_coordinateY = null;

        let distanceX = 0; //鼠标移动距离
        let distanceY = 0; //鼠标移动距离

        let isRounded = true;//是否有圆角

        // ****折线相关变量
        let pathString = ''; //绘制路径
        let currentPath;
        let isOver = false;//是否点击了右键完成当前折线的绘制

        let strench_Path = ""; //辅助路径标签
        let strench_currentPath;

        let currentPath_p; //铅笔相关
        let pathString_p = ''; //绘制路径

        let startX = 0;//等腰三角形始点坐标
        let startY = 0;
        // *****************************以下函数后续可进行封装
        function getRectangle(round) { //用按键模拟选中操作工具
            console.log("选中矩形工具");
            isDrawing = true;
            selectedShape = 1;
            isRounded = round; //选中的是否为圆角矩形
            isOver = true;
        };
        function getEllipise() { //用按键模拟选中操作工具
            console.log("选中圆形工具");
            isDrawing = true;
            selectedShape = 2;
            isOver = true;
        };
        function getLine() { //用按键模拟选中操作工具
            console.log("选中线段工具");
            isDrawing = true;
            selectedShape = 3;
            isOver = true;
        };
        function getPolyline() { //用按键模拟选中操作工具
            console.log("选中折线工具");
            isDrawing = true;
            selectedShape = 4;
            isOver = true;
        };
        function getPencile() { //用按键模拟选中操作工具
            console.log("选中铅笔工具");
            isDrawing = true;
            selectedShape = 5;
            isOver = true;
        };
        function getISOStriangle() { //用按键模拟选中操作工具
            console.log("选中ISOS三角形工具");
            isDrawing = true;
            selectedShape = 6;
            isOver = true;
        };

        function cancleChoose() { // 用按键模拟取消选中工具的操作
            console.log("cancle");
            isDrawing = false;
            selectedShape = null;
            isOver = true;
        };
        // *********************************************************

        svg.addEventListener("mousedown", function (event) {
            if (!isDrawing) { return } //若选中的不是当前绘图工具,则不执行以下操作

            if (event.button === 2) { //若鼠标右键被按下,则不绘制图形
                isDrawing = false; //结束绘制
            }

            const { offsetX, offsetY } = event;
            if (selectedShape === 2) {

                // 初始化添加标签----圆形
                newPath = document.createElementNS("http://www.w3.org/2000/svg", "ellipse");

                click_coordinateX = offsetX;
                click_coordinateY = offsetY;
                newPath.setAttribute("cx", offsetX);
                newPath.setAttribute("cy", offsetY);
                newPath.setAttribute("stroke", "black");
                newPath.setAttribute("fill", "#289");
            } else if (selectedShape == 1) {
                // 初始化添加标签----矩形
                newPath = document.createElementNS("http://www.w3.org/2000/svg", "rect");
                // 若为圆角矩形,则添加
                if (isRounded) {
                    newPath.setAttribute("rx", 20);
                    newPath.setAttribute("ry", 20);
                }

                click_coordinateX = offsetX;
                click_coordinateY = offsetY;
                newPath.setAttribute("x", offsetX);
                newPath.setAttribute("y", offsetY);
                newPath.setAttribute("stroke", "black");
                newPath.setAttribute("fill", "#619");
            } else if (selectedShape === 3) {
                // 初始化添加标签----线段
                newPath = document.createElementNS("http://www.w3.org/2000/svg", "line");
                click_coordinateX = offsetX;
                click_coordinateY = offsetY;
                newPath.setAttribute("x1", offsetX);
                newPath.setAttribute("y1", offsetY);
                newPath.setAttribute("x2", offsetX);
                newPath.setAttribute("y2", offsetY);
                newPath.setAttribute("stroke", "black");
                newPath.setAttribute("stroke-width", "2");
            } else if (selectedShape === 4) {

                if (event.button === 2) {
                    // 右键点击结束当前折线路径绘制
                    if (currentPath) {
                        isOver = true; //右键的话当前路径完结
                    }

                    // ************************************折线相关
                    // 右键点击后删除辅助标签
                    var element = document.getElementById("assistPath"); // 获取需要移除的元素
                    if (element) {
                        element.parentNode.removeChild(element);
                    }

                    // 如果只有一对坐标点时,清除对应的路径标签
                    if (pathString.trim().split(" ").length === 1) {
                        if (newPath) {
                            svg.removeChild(newPath);
                        }
                        pathString = "";
                        return;
                    }
                    return;
                }
                // debugger
                // 初始化添加标签或当前绘制完成添加下一个标签
                if (pathString === '' || isOver) {
                    newPath = document.createElementNS("http://www.w3.org/2000/svg", "polyline");
                    isOver = false;
                    pathString = "";

                }

                pathString += `${offsetX},${offsetY} `;
                newPath.setAttribute("points", pathString);
                newPath.setAttribute("stroke", "black");
                newPath.setAttribute("fill", "none");
                newPath.setAttribute("class", "wasChecked");
                currentPath = newPath;
                svg.appendChild(newPath);

                // 获取需要移除的元素
                var element = document.getElementById("assistPath");
                if (element) {
                    element.parentNode.removeChild(element);
                }
                // 创建辅助路径标签
                strench_Path = document.createElementNS("http://www.w3.org/2000/svg", "line");

                strench_Path.setAttribute("x1", offsetX);
                strench_Path.setAttribute("y1", offsetY);
                strench_Path.setAttribute("x2", offsetX);
                strench_Path.setAttribute("y2", offsetY);

                strench_Path.setAttribute("stroke", "#ffb27c");
                strench_Path.setAttribute("fill", "none");
                strench_Path.setAttribute("id", "assistPath");
                strench_currentPath = strench_Path;
                svg.appendChild(strench_Path);

            } else if (selectedShape === 5) {
                pathString_p = `M ${offsetX} ${offsetY}`;
                newPath = document.createElementNS("http://www.w3.org/2000/svg", "path");
                newPath.setAttribute("d", pathString_p);
                newPath.setAttribute("stroke", "black");
                newPath.setAttribute("fill", "none");
                currentPath_p = newPath;
            } else if (selectedShape === 6) {
                startX = offsetX;
                startY = offsetY;
                const pathString = `M ${startX} ${startY}`;
                currentPath = document.createElementNS("http://www.w3.org/2000/svg", "path");
                currentPath.setAttribute("d", pathString);
                currentPath.setAttribute("stroke", "black");
                currentPath.setAttribute("fill", "none");
                svg.appendChild(currentPath);
            }

            // 折线工具若没有右键退出绘制模式,切换到其他绘制图形时,会有折线的辅助直线保留,以下为直接选择其他工具时,清除辅助直线的
            var element = document.getElementById("assistPath"); // 获取需要移除的元素
            if (selectedShape !== 4 && element) {

                // ************************************折线相关
                // 右键点击后删除辅助标签
                if (element) {
                    element.parentNode.removeChild(element);
                }

                // 如果只有一对坐标点时,清除对应的路径标签
                if (pathString.trim().split(" ").length === 1) {
                    if (newPath) {
                        svg.removeChild(newPath);
                    }
                    pathString = "";
                    return;
                }
            }
            svg.appendChild(newPath);

        });

        svg.addEventListener("mousemove", function (event) {
            if (!isDrawing) return;
            const { offsetX, offsetY } = event;

            // 折线相关**********其对应的辅助路径要出现
            if (selectedShape == 4) {
                // 画辅助路径
                if (strench_currentPath) {
                    strench_Path.setAttribute("x2", offsetX);
                    strench_Path.setAttribute("y2", offsetY);
                }
            }


            if (event.buttons !== 1) { return }; //鼠标左键被按下
            // console.log("E", event);
            // 计算鼠标移动的距离获取获取长轴和短轴的值
            let rx = 0
            let ry = 0
            rx = Math.abs(click_coordinateX - offsetX);
            ry = Math.abs(click_coordinateY - offsetY);

            // 获取点击点到鼠标移动的距离
            let r_x;
            let r_y;
            r_x = Math.abs(click_coordinateX - rx);
            r_y = Math.abs(click_coordinateY - ry);

            if (selectedShape == 2) {
                // 若键盘按下shift键,则长短轴相等
                if (isShiftPressed) {
                    rx = ry = Number(rx) > Number(ry) ? rx : ry;
                }
                newPath.setAttribute("rx", rx);
                newPath.setAttribute("ry", ry);
            } else if (selectedShape == 1) {
                // 若键盘按下shift键,则长短轴相等
                if (isShiftPressed) {
                    rx = ry = Number(rx) > Number(ry) ? rx : ry;
                }
                newPath.setAttribute("width", rx);
                newPath.setAttribute("height", ry);

                // 重新获取 rect 标签的 x,y 值
                //0、 矩形在点击点的右下角时,使用原始点击点作为 x,y的值,其他情况如下
                if (click_coordinateX > offsetX && click_coordinateY > offsetY) { //1、在点击点的左上角
                    newPath.setAttribute("x", offsetX);
                    newPath.setAttribute("y", offsetY);
                } else if (click_coordinateX > offsetX) { //2、在点击点的左下角
                    newPath.setAttribute("x", r_x);
                } else if (click_coordinateY > offsetY) { //3、在点击点的右上角
                    newPath.setAttribute("y", r_y);
                }
            } else if (selectedShape == 3) {
                // 若键盘按下shift键,则线段情况为,横线,竖线,45°角的线段
                if (isShiftPressed) {

                    distanceX = Math.abs(offsetX - click_coordinateX);
                    distanceY = Math.abs(offsetY - click_coordinateY);
                    let c = distanceX * distanceX + distanceY * distanceY;

                    let angles = calculateAngleWithXAxis(click_coordinateX, click_coordinateY, offsetX, offsetY)
                    console.log("ag", angles);
                    if ((angles > -30 && angles < 30) || (angles < -150 || angles > 150)) {
                        newPath.setAttribute("x2", offsetX);
                        newPath.setAttribute("y2", click_coordinateY);
                    } else if ((angles < -60 && angles > -120) || (angles > 60 && angles < 120)) {
                        newPath.setAttribute("x2", click_coordinateX);
                        newPath.setAttribute("y2", offsetY);
                    } else if ((angles >= 120 && angles < 150)) {
                        let side = distanceY > distanceX ? distanceY : distanceX;
                        newPath.setAttribute("x2", click_coordinateX - side);
                        newPath.setAttribute("y2", click_coordinateY + side);
                    } else if ((angles > -150 && angles < -120)) {
                        let side = distanceY > distanceX ? distanceY : distanceX;
                        newPath.setAttribute("x2", click_coordinateX - side);
                        newPath.setAttribute("y2", click_coordinateY - side);
                    } else if ((angles > -60 && angles < -30)) {
                        let side = distanceY > distanceX ? distanceY : distanceX;
                        newPath.setAttribute("x2", click_coordinateX + side);
                        newPath.setAttribute("y2", click_coordinateY - side);
                    } else if ((angles > 30 && angles < 60)) {
                        let side = distanceY > distanceX ? distanceY : distanceX;
                        newPath.setAttribute("x2", click_coordinateX + side);
                        newPath.setAttribute("y2", click_coordinateY + side);
                    }
                } else {
                    // 没有按下shift键的线段情况
                    newPath.setAttribute("x2", offsetX);
                    newPath.setAttribute("y2", offsetY);
                }

            } else if (selectedShape == 5) {
                if (currentPath_p) {
                    pathString_p += ` L ${offsetX} ${offsetY}`;
                    currentPath_p.setAttribute("d", pathString_p);
                }
            } else if (selectedShape === 6) {
                let endX = offsetX;
                let endY = offsetY;
                if (event.shiftKey) {
                    // 如果按下 Shift 键,则将三角形转换为等边三角形
                    const sideLength = Math.min(Math.abs(endX - startX), Math.abs(endY - startY));
                    endX = startX + (endX > startX ? sideLength : -sideLength);
                    endY = startY + (endY > startY ? sideLength : -sideLength);
                }

                const path = `M ${startX} ${startY} L ${endX} ${endY} L ${2 * startX - endX} ${endY} Z`;
                currentPath.setAttribute("d", path);
            }
        });

        svg.addEventListener("mouseup", function (event) {
            const { offsetX, offsetY } = event;
            const childNodes = Array.from(svg.childNodes);
            // console.log("selectedShape", selectedShape);
            childNodes.forEach(node => {
                // console.log("node", node);
                if (node.nodeName === "ellipse") {
                    let rx = node?.getAttribute("rx");
                    let ry = node?.getAttribute("ry");
                    // 长轴或短轴不存在或其值小于1时,移除此dom元素
                    if ((!rx || !ry) || Number(rx) < 1 || Number(ry) < 1) {
                        svg.removeChild(node);
                    }
                } else if (node.nodeName === "rect") {
                    let w = node?.getAttribute("width");
                    let h = node?.getAttribute("height");
                    // 长轴或短轴不存在或其值小于1时,移除此dom元素
                    if ((!w || !h) || Number(w) < 1 || Number(h) < 1) {
                        svg.removeChild(node);
                    }
                } else if (node.nodeName === "line" && selectedShape == 3) {

                    let dx = Math.abs(node.getAttribute("x2") - node.getAttribute("x1"));
                    let dy = Math.abs(node.getAttribute("y2") - node.getAttribute("y1"));
                    // 线段的位移小于2时,移除对应的dom
                    if (dx < 2 && dy < 2) {
                        svg.removeChild(node);
                    }
                } else if (node.nodeName === "path") {
                    // 若路径中没有包含L,则说明只是进行了点击,并未移动生成路径,所以删除对应的标签
                    let d = node.getAttribute("d")
                    if (!d.includes("L")) {
                        svg.removeChild(node);
                    }
                }

            });
        })

        svg.addEventListener("contextmenu", function (event) {
            event.preventDefault();

        });

        // 监听键盘按下事件
        document.addEventListener('keydown', function (event) {
            // console.log('Key pressed:', event);
            if (event.key === 'Shift') {  // 检查特定按键
                isShiftPressed = true;
            }
        });

        // 监听键盘释放事件
        document.addEventListener('keyup', function (event) {
            if (event.key === 'Shift') {
                isShiftPressed = false;
            }
        });

        // 计算线段与X轴夹角
        function calculateAngleWithXAxis(x1, y1, x2, y2) {
            let angleRadians = Math.atan2(y2 - y1, x2 - x1);
            let angleDegrees = angleRadians * (180 / Math.PI);

            return angleDegrees;
        }

    </script>
</body>

</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值