HTML代码手搓2D绘图软件 禁止任何转载商用这是简易2D绘图软件HTML代码。它是一款基于Canvas的矢量绘图工具支持绘制直线、矩形和圆形。html!DOCTYPE htmlhtml langzh-CNheadmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0title简易2D绘图软件/titlestyle* {box-sizing: border-box;user-select: none;}body {background: #2b2b3a;display: flex;justify-content: center;align-items: center;min-height: 100vh;margin: 0;font-family: Segoe UI, Roboto, system-ui, sans-serif;}.draw-app {background: #1e1e2a;border-radius: 28px;padding: 24px 28px 30px 28px;box-shadow: 0 18px 30px rgba(0,0,0,0.6);display: flex;flex-direction: column;align-items: center;}.toolbar {display: flex;flex-wrap: wrap;align-items: center;gap: 10px 14px;background: #2d2d40;padding: 12px 22px;border-radius: 60px;margin-bottom: 20px;box-shadow: inset 0 2px 5px rgba(0,0,0,0.4);}.tool-group {display: flex;gap: 6px;align-items: center;}.tool-btn {background: #3d3d55;border: none;color: #d0d0e0;font-size: 15px;font-weight: 500;padding: 8px 16px;border-radius: 40px;cursor: pointer;transition: 0.15s;letter-spacing: 0.3px;box-shadow: 0 2px 3px rgba(0,0,0,0.3);min-width: 58px;}.tool-btn:hover {background: #5a5a7a;color: white;transform: scale(1.02);}.tool-btn.active {background: #7f7fb0;color: white;box-shadow: 0 0 0 2px #b8b8f0;}.color-picker-wrap {display: flex;align-items: center;gap: 10px;background: #2a2a3e;padding: 4px 14px 4px 10px;border-radius: 40px;}.color-picker-wrap label {color: #c8c8e0;font-size: 14px;font-weight: 400;}input[typecolor] {width: 34px;height: 34px;border: 2px solid #5a5a7a;border-radius: 30px;background: transparent;cursor: pointer;padding: 2px;}input[typecolor]::-webkit-color-swatch-wrapper {padding: 0;}input[typecolor]::-webkit-color-swatch {border: none;border-radius: 30px;}.clear-btn {background: #4d3f4a;color: #f0d0d0;border: none;padding: 8px 20px;border-radius: 40px;font-weight: 500;font-size: 14px;cursor: pointer;transition: 0.15s;box-shadow: 0 2px 3px rgba(0,0,0,0.3);}.clear-btn:hover {background: #6f4f5a;color: white;}.canvas-wrapper {background: #fcf9f2;border-radius: 22px;padding: 8px;box-shadow: inset 0 0 0 1px #4a4a5e, 0 12px 24px rgba(0,0,0,0.5);}canvas {display: block;width: 720px;height: 480px;border-radius: 16px;background: #ffffff;cursor: crosshair;box-shadow: 0 0 0 1px #8a8aa0;}.status-bar {margin-top: 14px;color: #a8a8c0;font-size: 14px;background: #262636;padding: 6px 24px;border-radius: 60px;letter-spacing: 0.3px;box-shadow: inset 0 1px 4px #0f0f18;}.status-bar span {color: #d4d4f0;font-weight: 500;}/style/headbodydiv classdraw-appdiv classtoolbardiv classtool-groupbutton classtool-btn active data-toolline 直线/buttonbutton classtool-btn data-toolrect▭ 矩形/buttonbutton classtool-btn data-toolcircle⬤ 圆形/button/divdiv classcolor-picker-wraplabel forstrokeColor️ 颜色/labelinput typecolor idstrokeColor value#1f3a6b/divbutton classclear-btn idclearCanvas️ 清空/button/divdiv classcanvas-wrappercanvas iddrawCanvas width720 height480/canvas/divdiv classstatus-barspan idtoolStatus直线/span · 拖拽绘制 · 点击颜色可更换/div/divscript(function() {const canvas document.getElementById(drawCanvas);const ctx canvas.getContext(2d);const toolStatus document.getElementById(toolStatus);// ---------- 状态 ----------let currentTool line; // line, rect, circlelet strokeColor #1f3a6b;let isDrawing false;let startX 0, startY 0;let currentX 0, currentY 0;// 存储所有已绘制的图形 (用于重绘)let shapes [];// ---------- 辅助函数 ----------function getCanvasCoords(e) {const rect canvas.getBoundingClientRect();const scaleX canvas.width / rect.width; // canvas物理尺寸与CSS比例const scaleY canvas.height / rect.height;const clientX e.clientX || e.touches?.[0]?.clientX || 0;const clientY e.clientY || e.touches?.[0]?.clientY || 0;return {x: (clientX - rect.left) * scaleX,y: (clientY - rect.top) * scaleY};}// 重绘所有图形 (包括当前正在绘制的预览)function redraw(includeTemp true) {ctx.clearRect(0, 0, canvas.width, canvas.height);// 绘制所有已保存的图形for (let s of shapes) {ctx.beginPath();ctx.strokeStyle s.color;ctx.lineWidth 2.5;ctx.lineJoin round;ctx.lineCap round;if (s.type line) {ctx.moveTo(s.x1, s.y1);ctx.lineTo(s.x2, s.y2);ctx.stroke();} else if (s.type rect) {const x Math.min(s.x1, s.x2);const y Math.min(s.y1, s.y2);const w Math.abs(s.x2 - s.x1);const h Math.abs(s.y2 - s.y1);ctx.strokeRect(x, y, w, h);} else if (s.type circle) {const cx (s.x1 s.x2) / 2;const cy (s.y1 s.y2) / 2;const rx Math.abs(s.x2 - s.x1) / 2;const ry Math.abs(s.y2 - s.y1) / 2;const radius Math.max(rx, ry); // 使用最大半径更自然ctx.ellipse(cx, cy, radius, radius, 0, 0, Math.PI * 2);ctx.stroke();}}// 绘制当前临时图形 (拖拽中)if (includeTemp isDrawing) {ctx.beginPath();ctx.strokeStyle strokeColor;ctx.lineWidth 2.5;ctx.lineJoin round;ctx.lineCap round;const temp {type: currentTool,x1: startX, y1: startY,x2: currentX, y2: currentY,color: strokeColor};if (temp.type line) {ctx.moveTo(temp.x1, temp.y1);ctx.lineTo(temp.x2, temp.y2);ctx.stroke();} else if (temp.type rect) {const x Math.min(temp.x1, temp.x2);const y Math.min(temp.y1, temp.y2);const w Math.abs(temp.x2 - temp.x1);const h Math.abs(temp.y2 - temp.y1);ctx.strokeRect(x, y, w, h);} else if (temp.type circle) {const cx (temp.x1 temp.x2) / 2;const cy (temp.y1 temp.y2) / 2;const rx Math.abs(temp.x2 - temp.x1) / 2;const ry Math.abs(temp.y2 - temp.y1) / 2;const radius Math.max(rx, ry);ctx.ellipse(cx, cy, radius, radius, 0, 0, Math.PI * 2);ctx.stroke();}}}// ---------- 图形完成 (保存到shapes) ----------function finishShape(x2, y2) {if (startX x2 startY y2) {// 点一下不生成图形return;}const shape {type: currentTool,x1: startX, y1: startY,x2: x2, y2: y2,color: strokeColor};shapes.push(shape);redraw(false); // 重绘时不包含临时图形 (已经保存)}// ---------- 事件绑定 ----------function onPointerDown(e) {e.preventDefault();const coord getCanvasCoords(e);isDrawing true;startX coord.x;startY coord.y;currentX startX;currentY startY;redraw(true);}function onPointerMove(e) {e.preventDefault();if (!isDrawing) {// 可以不做任何事但为了显示坐标可扩展return;}const coord getCanvasCoords(e);currentX coord.x;currentY coord.y;redraw(true);}function onPointerUp(e) {e.preventDefault();if (!isDrawing) return;const coord getCanvasCoords(e);const endX coord.x;const endY coord.y;// 如果鼠标松开时位置与起点不同则完成图形if (Math.abs(endX - startX) 1 || Math.abs(endY - startY) 1) {finishShape(endX, endY);} else {// 小偏移也当作点击不生成图形但需要清除临时状态redraw(false);}isDrawing false;// 重置临时坐标startX 0; startY 0;currentX 0; currentY 0;}// 鼠标事件canvas.addEventListener(mousedown, onPointerDown);window.addEventListener(mousemove, (e) {if (!isDrawing) return;onPointerMove(e);});window.addEventListener(mouseup, onPointerUp);// 触摸事件 (移动端支持)canvas.addEventListener(touchstart, (e) {e.preventDefault();const touch e.touches[0];if (!touch) return;const mouseEvent new MouseEvent(mousedown, {clientX: touch.clientX,clientY: touch.clientY,});canvas.dispatchEvent(mouseEvent);}, { passive: false });window.addEventListener(touchmove, (e) {if (!isDrawing) return;e.preventDefault();const touch e.touches[0];if (!touch) return;const mouseEvent new MouseEvent(mousemove, {clientX: touch.clientX,clientY: touch.clientY,});window.dispatchEvent(mouseEvent);}, { passive: false });window.addEventListener(touchend, (e) {if (!isDrawing) return;e.preventDefault();const mouseEvent new MouseEvent(mouseup, {});window.dispatchEvent(mouseEvent);}, { passive: false });// ---------- 工具栏切换 ----------document.querySelectorAll(.tool-btn).forEach(btn {btn.addEventListener(click, () {document.querySelectorAll(.tool-btn).forEach(b b.classList.remove(active));btn.classList.add(active);currentTool btn.dataset.tool;const toolNameMap { line: 直线, rect: 矩形, circle: 圆形 };toolStatus.textContent toolNameMap[currentTool] || 直线;// 切换工具时如果有绘制中的状态取消if (isDrawing) {isDrawing false;redraw(false);}});});// ---------- 颜色选择 ----------document.getElementById(strokeColor).addEventListener(input, (e) {strokeColor e.target.value;// 如果有正在绘制的图形更新颜色实时预览 (redraw会使用strokeColor)if (isDrawing) {redraw(true);}});// ---------- 清空 ----------document.getElementById(clearCanvas).addEventListener(click, () {shapes [];if (isDrawing) {isDrawing false;}redraw(false);});// ---------- 初始化 绘制一个示例图形 (让人知道可以用) ----------function initDemo() {shapes [{ type: line, x1: 80, y1: 100, x2: 280, y2: 200, color: #aa4a6b },{ type: rect, x1: 350, y1: 80, x2: 550, y2: 220, color: #2a6b4a },{ type: circle, x1: 480, y1: 350, x2: 620, y2: 410, color: #3f5f9f },{ type: line, x1: 40, y1: 380, x2: 200, y2: 420, color: #b06a3a },];redraw(false);toolStatus.textContent 直线;}initDemo();// 额外如果颜色改变时更新示例颜色没必要但保留一致性// 窗口失焦时如果有绘制不丢失// 处理canvas尺寸变化 (保持比例)})();/script/body/html绘图工具的使用与交互可以通过简单的拖拽来创建图形界面设计直观易于上手。1. 选择图形工具点击工具栏上的“直线”、“矩形”或“圆形”按钮即可切换当前绘图模式。2. 绘制图形在画布上按住并拖拽鼠标即可绘制出对应形状。松开鼠标后图形将被固定并保存。3. 自定义样式可以通过颜色选择器更改当前图形的轮廓颜色所有新绘制的图形都将使用此颜色。4. 管理作品点击“清空”按钮可以一键删除画布上的所有图形方便重新开始创作。