个人电子白板(svg标签电子画板功能包含正方形、文本、橡皮 (颜色、尺寸、不透明度)、 撤销、取消撤销 等等功能,)

在Http开发中,svg标签电子画板功能包含正方形、文本、橡皮 (颜色、尺寸、不透明度)、 撤销、取消撤销 等等功能,

效果图

代码如下:

<!DOCTYPE html>
<html lang="en">
<!--
    <link href="/Index/css/materialdesignicons.min.css" rel="stylesheet">
-->
<head>
    <meta charset="utf-8"/>
    <title>电子白板</title>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/>

    <!--    <meta name="description" content="{{translations.tagline}}" />
        <meta name="keywords" content="{{translations.collaborative_whiteboard}},online,draw,paint,shared,realtime,wbo,whitebophir" />
        <meta property="og:title" content="{{board}} board on WBO" />
        <meta property="og:url" content="{{baseUrl}}/boards/{{boardUriComponent}}" />
        <meta property="og:image" content="{{baseUrl}}/preview/{{boardUriComponent}}" />-->

    <!--    <link rel="apple-touch-icon" href="/WhiteBoard/img/favicon.svg">-->
    <link rel="stylesheet" type="text/css" href="/WhiteBoard/css/board.css"/>
    <!--    <link rel="canonical" href="{{boardUriComponent}}?lang={{language}}" />
        {{#languages}}
        <link rel="alternate" hreflang="{{.}}" href="{{../boardUriComponent}}?lang={{.}}" />
        {{/languages}}-->

</head>

<style>
    body, html {
        margin: 0;
        padding: 0;
        height: 100%;
    }
    svg {
        width: 100%;
        height: 100%;
    }


    #textInputContainer {
        position: absolute;
        display: none;
        background: white;
        padding: 5px;
        border: 1px solid #ccc;
        box-shadow: 0 0 5px rgba(0,0,0,0.2);
    }

    #textInput {
        width: 200px;
        padding: 5px;
    }
</style>
<body>

<div id="board" style="width:100%; height:100%;">
    <svg id="drawing-board"  version="1.1" xmlns="http://www.w3.org/2000/svg">
        <defs id="defs"></defs>
        <g id="drawingArea"></g>
        <g id="cursors"></g>

    </svg>
</div>


<div id="loadingMessage" class="hidden">载入中</div>

<div id="menu" tabindex="0">
    <div id="menuItems">
        <ul id="tools" class="tools">
            <li class="tool hasSecondary curTool" tabindex="-1" id="pencil" title="铅笔" onclick="toolFun('pencil')">
                <img class="tool-icon primaryIcon" width="35" height="35" src="/WhiteBoard/tools/pencil/icon.svg"
                     alt="/WhiteBoard/tools/pencil/icon.svg"/>
                <span class="tool-name">铅笔</span>
                <img class="tool-icon secondaryIcon" width="35" height="35"
                     src="/WhiteBoard/tools/pencil/whiteout_tape.svg" alt="icon"/>
            </li>
            <li class="tool hasSecondary" tabindex="-1" id="line" title="直线 " onclick="toolFun('line')" >
                <img class="tool-icon" width="35" height="35" src="/WhiteBoard/tools/line/icon.svg"
                     alt="/WhiteBoard/tools/pencil/icon.svg"/>
                <span class="tool-name">直线</span>
                <img class="tool-icon secondaryIcon" width="35" height="35"
                     src="/WhiteBoard/tools/line/icon-straight.svg" alt="icon"/>
            </li>
            <li class="tool hasSecondary" tabindex="-1" id="rect" title="矩形" onclick="toolFun('rect')" >
                <img class="tool-icon primaryIcon" width="35" height="35" src="/WhiteBoard/tools/rect/icon.svg"
                     alt="/WhiteBoard/tools/rect/icon.svg">
                <span class="tool-name">矩形</span>
                <img class="tool-icon secondaryIcon" width="35" height="35" src="/WhiteBoard/tools/rect/icon-square.svg"
                     alt="icon">
            </li>
            <li class="tool hasSecondary" tabindex="-1" id="ellipse" title="椭圆" onclick="toolFun('ellipse')">
                <img class="tool-icon primaryIcon" width="35" height="35"
                     src="/WhiteBoard/tools/ellipse/icon-ellipse.svg" alt="/WhiteBoard/tools/ellipse/icon-ellipse.svg">
                <span class="tool-name">椭圆</span>
                <img class="tool-icon secondaryIcon" width="35" height="35"
                     src="/WhiteBoard/tools/ellipse/icon-circle.svg" alt="icon">
            </li>
            <li class="tool" tabindex="-1" id="text" title="文本" onclick="toolFun('text')">
                <img class="tool-icon" width="35" height="35" src="/WhiteBoard/tools/text/icon.svg"
                     alt="/WhiteBoard/tools/text/icon.svg">
                <span class="tool-name">文本</span>
                <img class="tool-icon secondaryIcon" width="35" height="35" src="data:," alt="icon">
            </li>
            <li class="tool" tabindex="-1" id="eraser" title="橡皮 " onclick="toolFun('eraser')" >
                <img class="tool-icon" width="35" height="35" src="/WhiteBoard/tools/eraser/icon.svg"
                     alt="/WhiteBoard/tools/eraser/icon.svg">
                <span class="tool-name">橡皮</span>
                <img class="tool-icon secondaryIcon" width="35" height="35" src="data:," alt="icon">
            </li>
<!--            <li class="tool hasSecondary curTool" tabindex="-1" id="toolID-Hand" title="移动 (键盘快捷键: h) [点击以切换]">
                <img class="tool-icon primaryIcon" width="35" height="35" src="/WhiteBoard/tools/hand/hand.svg"
                     alt="/WhiteBoard/tools/hand/hand.svg">
                <span class="tool-name">移动</span>
                <img class="tool-icon secondaryIcon" width="35" height="35" src="/WhiteBoard/tools/hand/selector.svg"
                     alt="icon">
            </li>
            <li class="tool oneTouch" tabindex="-1" id="toolID-Grid" title="网格 (键盘快捷键: g)">
                <img class="tool-icon" width="35" height="35" src="/WhiteBoard/tools/grid/icon.svg"
                     alt="/WhiteBoard/tools/grid/icon.svg">
                <span class="tool-name">网格</span>
                <img class="tool-icon secondaryIcon" width="35" height="35" src="data:," alt="icon">
            </li>
            <li class="tool oneTouch" tabindex="-1" id="toolID-Download" title="下载 (键盘快捷键: d)">
                <img class="tool-icon" width="35" height="35" src="/WhiteBoard/tools/download/download.svg"
                     alt="/WhiteBoard/tools/download/download.svg">
                <span class="tool-name">下载</span>
                <img class="tool-icon secondaryIcon" width="35" height="35" src="data:," alt="icon">
            </li>
            <li class="tool" tabindex="-1" id="toolID-Zoom" title="放大 (键盘快捷键: z)">
                <img class="tool-icon" width="35" height="35" src="/WhiteBoard/tools/zoom/icon.svg"
                     alt="/WhiteBoard/tools/zoom/icon.svg">
                <span class="tool-name">放大</span>
                <img class="tool-icon secondaryIcon" width="35" height="35" src="data:," alt="icon">
            </li>-->
        </ul>

        <ul class="tools" id="settings">
            <li class="tool" tabindex="-1">
                <input class="tool-icon" type="color" id="chooseColor" value="#001f3f">
                <label class="tool-name" for="chooseColor">颜色</label>
                <span class="colorPresets" id="colorPreset"  title="001f3f"  >
                    <span class="colorPresetButton" id="color_001f3f" title="#001f3f" style="background-color: rgb(0, 31, 63);"></span>
                    <span class="colorPresetButton" id="color_FF4136" title="#FF4136" style="background-color: rgb(255, 65, 54);"></span>
                    <span class="colorPresetButton" id="color_0074D9" title="#0074D9" style="background-color: rgb(0, 116, 217);"></span>
                    <span class="colorPresetButton" id="color_FF851B" title="#FF851B" style="background-color: rgb(255, 133, 27);"></span>
                    <span class="colorPresetButton" id="color_FFDC00" title="#FFDC00" style="background-color: rgb(255, 220, 0);"></span>
                    <span class="colorPresetButton" id="color_3D9970" title="#3D9970" style="background-color: rgb(61, 153, 112);"></span>
                    <span class="colorPresetButton" id="color_91E99B" title="#91E99B" style="background-color: rgb(145, 233, 155);"></span>
                    <span class="colorPresetButton" id="color_90468b" title="#90468b" style="background-color: rgb(144, 70, 139);"></span>
                    <span class="colorPresetButton" id="color_7FDBFF" title="#7FDBFF" style="background-color: rgb(127, 219, 255);"></span>
                    <span class="colorPresetButton" id="color_AAAAAA" title="#AAAAAA" style="background-color: rgb(170, 170, 170);"></span>
                    <span class="colorPresetButton" id="color_E65194" title="#E65194" style="background-color: rgb(230, 81, 148);"></span>
                </span>
            </li>

            <li class="tool" tabindex="-1" title="尺寸 ">
                <img class="tool-icon" width="60" height="60" src="/WhiteBoard/img/icon-size.svg" alt="size">
                <label class="tool-name slider" for="size">
                    <span>尺寸</span>
                    <input type="range" id="size" value="4" min="1" max="50" step="1" class="rangeChooser">
                </label>
            </li>

            <li class="tool" tabindex="-1">
					<span class="tool-icon">
						<svg viewBox="0 0 8 8">
							<pattern id="opacityPattern" x="0" y="0" width="4" height="4" patternUnits="userSpaceOnUse">
								<rect x="0" y="0" width="2" height="2" fill="black"></rect>
								<rect x="2" y="2" width="2" height="2" fill="black"></rect>
								<rect x="2" y="0" width="2" height="2" fill="#eeeeee"></rect>
								<rect x="0" y="2" width="2" height="2" fill="#eeeeee"></rect>
							</pattern>
							<circle cx="4" cy="4" id="opacityIndicator" r="3.5" fill="url(#opacityPattern)" opacity="1"></circle>
						</svg>
					</span>
                <label class="tool-name slider" for="chooseOpacity">
                    <span>不透明度</span>
                    <input type="range" id="chooseOpacity" value="1" min="0.2" max="1" step="0.1" class="rangeChooser">
                </label>
            </li>
            </li>

            <li class="tool hasSecondary" tabindex="-1" id="undo" title="上一步" >
                <img class="tool-icon primaryIcon" width="35" height="35" src="/WhiteBoard/tools/img/undo.svg" >
                <span class="tool-name">上一步</span>
            </li>
            <li class="tool hasSecondary" tabindex="-1" id="redo" title="下一步" >
                <img class="tool-icon primaryIcon" width="35" height="35" src="/WhiteBoard/tools/img/redo.svg" >
                <span class="tool-name">下一步</span>
            </li>
        </ul>
    </div>
</div>

<div id="textInputContainer">
    <input type="text" id="textInput" placeholder="输入文本">
    <button id="textConfirm">确定</button>
    <button id="textCancel">取消</button>
</div>
<script type="text/javascript" src="/js/jquery-3.6.0.js"></script>
<script type="text/javascript" src="/js/axios.js"></script>

<script>
    const tools_lis = document.getElementById('tools').getElementsByTagName("li");
    const drawingBoard = document.getElementById('drawing-board');
    const pencilBtn = document.getElementById('pencil');
    const lineBtn = document.getElementById('line');
    const ellipseBtn = document.getElementById('ellipse');
    const rectBtn = document.getElementById('rect');
    const textBtn = document.getElementById('text');
    const eraserBtn = document.getElementById('eraser');
    const colorInput = document.getElementById('colorPreset');
    const sizeInput = document.getElementById('size');
    const opacityInput = document.getElementById('chooseOpacity');
    const undoBtn = document.getElementById('undo');
    const redoBtn = document.getElementById('redo');
    //text
    const textInputContainer = document.getElementById('textInputContainer');
    const textInput = document.getElementById('textInput');
    const textConfirm = document.getElementById('textConfirm');
    const textCancel = document.getElementById('textCancel');


    let currentTool = 'pencil';
    let isDrawing = false;
    let startX, startY;
    let path;
    let lines = [];
    let undoStack = [];
    let redoStack = [];


    //工具选择
    function toolFun(e) {
        for (let j = 0; j < tools_lis.length; j++) {
            tools_lis[j].classList.remove('curTool');
        }
        currentTool = e;
        document.getElementById(e).classList.add('curTool');
        cancelText();
    }
    //颜色选择
    var colorSpans = colorInput.getElementsByTagName("span");
    for (let i = 0; i < colorSpans.length; i++) {
        colorSpans[i].addEventListener('click', function () {
            $("#chooseColor").val(this.title);
        });
    }
    // 文本输入相关
    textConfirm.addEventListener('click', confirmText);
    textCancel.addEventListener('click', cancelText);
    drawingBoard.addEventListener('click', handleCanvasClick);

    drawingBoard.addEventListener('mousedown', (e) => {
        isDrawing = true;
        startX = e.offsetX;
        startY = e.offsetY;

        if (currentTool === 'pencil') {
            path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
            path.setAttribute('d', `M${startX} ${startY}`);
            path.setAttribute('stroke', $("#chooseColor").val());
            path.setAttribute('stroke-width', sizeInput.value);
            path.setAttribute('fill', 'none');
            path.setAttribute('opacity', opacityInput.title);
            drawingBoard.appendChild(path);
            lines.push(path);
        } else if (currentTool === 'line') {
            const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
            line.setAttribute('x1', startX);
            line.setAttribute('y1', startY);
            line.setAttribute('x2', startX);
            line.setAttribute('y2', startY);
            line.setAttribute('stroke', $("#chooseColor").val());
            line.setAttribute('stroke-width', sizeInput.value);
            line.setAttribute('opacity', opacityInput.value);
            drawingBoard.appendChild(line);
            lines.push(line);
        } else if (currentTool === 'ellipse') {
            const ellipse = document.createElementNS('http://www.w3.org/2000/svg', 'ellipse');
            ellipse.setAttribute('cx', startX);
            ellipse.setAttribute('cy', startY);
            ellipse.setAttribute('rx', 0);
            ellipse.setAttribute('ry', 0);
            ellipse.setAttribute('fill', 'none');
            ellipse.setAttribute('stroke-width', sizeInput.value);
            ellipse.setAttribute('stroke', $("#chooseColor").val());
            ellipse.setAttribute('opacity', opacityInput.value);
            drawingBoard.appendChild(ellipse);
            lines.push(ellipse);
        } else if (currentTool === 'rect') {
            const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
            rect.setAttribute('x', startX);
            rect.setAttribute('y', startY);
            rect.setAttribute('width', 0);
            rect.setAttribute('height', 0);
            rect.setAttribute('fill', 'none');
            rect.setAttribute('stroke-width', sizeInput.value);
            rect.setAttribute('stroke', $("#chooseColor").val());
            rect.setAttribute('opacity', opacityInput.value);
            drawingBoard.appendChild(rect);
            lines.push(rect);
        }
        else if (currentTool === 'eraser') {
            const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
            rect.setAttribute('x', startX);
            rect.setAttribute('y', startY);
            rect.setAttribute('width', 0);
            rect.setAttribute('height', 0);
            rect.setAttribute('fill', 'none');
            rect.setAttribute('stroke-width', 2);
            rect.setAttribute('stroke', "#000000");
            rect.setAttribute('stroke-dasharray', "10 5");
            drawingBoard.appendChild(rect);
            lines.push(rect);
        }

    });

    drawingBoard.addEventListener('mousemove', (e) => {
        if (isDrawing) {
            if (currentTool === 'pencil') {
                const d = path.getAttribute('d');
                path.setAttribute('d', `${d} L${e.offsetX} ${e.offsetY}`);
            } else if (currentTool === 'line') {
                const lastLine = lines[lines.length - 1];
                lastLine.setAttribute('x2', e.offsetX);
                lastLine.setAttribute('y2', e.offsetY);
            } else if (currentTool === 'ellipse') {
                const lastEllipse = lines[lines.length - 1];
                const dx = e.offsetX - startX;
                const dy = e.offsetY - startY;
                lastEllipse.setAttribute('rx', Math.abs(dx));
                lastEllipse.setAttribute('ry', Math.abs(dy));
            } else if (currentTool === 'rect') {
                const lastRect = lines[lines.length - 1];
                const dx = e.offsetX - startX;
                const dy = e.offsetY - startY;
                lastRect.setAttribute('width', Math.abs(dx));
                lastRect.setAttribute('height', Math.abs(dy));
                if (dx < 0) {
                    lastRect.setAttribute('x', e.offsetX);
                }
                if (dy < 0) {
                    lastRect.setAttribute('y', e.offsetY);
                }
            }
            else if (currentTool === 'eraser'){
                const lastRect = lines[lines.length - 1];
                const dx = e.offsetX - startX;
                const dy = e.offsetY - startY;
                lastRect.setAttribute('width', Math.abs(dx));
                lastRect.setAttribute('height', Math.abs(dy));
                if (dx < 0) {
                    lastRect.setAttribute('x', e.offsetX);
                }
                if (dy < 0) {
                    lastRect.setAttribute('y', e.offsetY);
                }
            }
        }
    });

    drawingBoard.addEventListener('mouseup', () => {
        if (currentTool === 'eraser'){
            const lastRect = lines[lines.length - 1];

            lastRect.setAttribute('fill', '#ffffff');
            lastRect.setAttribute('stroke-width', 2);
            lastRect.setAttribute('stroke', "#ffffff");
            lastRect.setAttribute('stroke-dasharray', "0");
        }

        isDrawing = false;



        if (lines.length > 0) {
            const lastElement = lines.pop();
            undoStack.push(lastElement);
            redoStack = [];
        }
    });

    undoBtn.addEventListener('click', () => {
        if (undoStack.length > 0) {
            const lastElement = undoStack.pop();
            drawingBoard.removeChild(lastElement);
            redoStack.push(lastElement);
        }
    });

    redoBtn.addEventListener('click', () => {
        if (redoStack.length > 0) {
            const lastElement = redoStack.pop();
            drawingBoard.appendChild(lastElement);
            undoStack.push(lastElement);
        }
    });

    function handleCanvasClick(e) {
        if (currentTool === 'text') {
            showTextInput(e.offsetX, e.offsetY);
        }
    }

    function showTextInput(x, y) {
        textInputContainer.style.display = 'block';
        textInputContainer.style.left = x + 'px';
        textInputContainer.style.top = y + 'px';
        textInput.focus();
    }

    // 4 -- 36
    // 50 -- 87 = 37
    // 1 ---13 == 12
    function confirmText() {
        const text = textInput.value.trim();
        if (text) {
            console.log(textInputContainer.style);
            console.log(textInputContainer.style.left);
            console.log(textInputContainer.style.top);
            const x = parseInt(textInputContainer.style.left) ;  //- rect.left
            const y = parseInt(textInputContainer.style.top) ; // 稍微下移 - rect.top
            const textElement = document.createElementNS('http://www.w3.org/2000/svg', 'text');
            textElement.textContent = text;
            textElement.setAttribute('x', x);
            textElement.setAttribute('y', y);
            textElement.setAttribute('font-size', 18+(sizeInput.value*1.5));
            textElement.setAttribute('fill', $("#chooseColor").val());
            textElement.setAttribute('opacity', opacityInput.value);
            drawingBoard.appendChild(textElement);


            lines.push(textElement);

            if (lines.length > 0) {
                const lastElement = lines.pop();
                undoStack.push(lastElement);
                redoStack = [];
            }
        }

        cancelText();
    }

    function cancelText() {
        textInput.value = '';
        textInputContainer.style.display = 'none';
    }
</script>
</body>

</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值