个人电子白板(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');//textconst 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 == 12function 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.leftconst y = parseInt(textInputContainer.style.top) ; // 稍微下移 - rect.topconst 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>