WordPress+Elementor中Canvas绘图鼠标偏移问题求助
WordPress + Elementor中Canvas绘图光标偏移问题修复
问题描述
我想在WordPress里通过Elementor的HTML元素实现交互式绘图功能,代码在WordPress外部运行正常,但部署后鼠标绘制位置和光标出现明显偏移。尝试过调整Canvas尺寸、移除边距,问题仍未解决。
核心原因
- Canvas实际尺寸与显示尺寸脱节:原代码用
window.innerWidth计算Canvas的绘图缓冲区尺寸,但Elementor的嵌套容器会通过CSS缩放Canvas的显示尺寸,导致坐标映射错误。 - 偏移计算逻辑错误:
canvas.offsetLeft/offsetTop在Elementor的复杂布局中计算不准确,且未考虑窗口滚动的影响,同时e.clientY未减去Canvas的垂直偏移。 - 静态偏移值未更新:页面加载后如果元素位置因响应式布局变化,原代码中的静态偏移值不会自动刷新。
修复方案
1. 同步Canvas绘图尺寸与显示尺寸
不要用固定值设置Canvas尺寸,而是实时获取它在页面中的显示尺寸,同步到绘图缓冲区:
function resizeCanvas() { const rect = canvas.getBoundingClientRect(); canvas.width = rect.width; canvas.height = rect.height; } // 页面加载和窗口大小变化时触发 window.addEventListener('load', resizeCanvas); window.addEventListener('resize', resizeCanvas);
2. 正确计算鼠标在Canvas内的坐标
用getBoundingClientRect()实时获取Canvas的位置,同时考虑窗口滚动的影响,确保坐标精准映射:
const draw = (e) => { if(!isPainting) return; ctx.lineWidth = lineWidth; ctx.lineCap = 'round'; const rect = canvas.getBoundingClientRect(); // 计算相对Canvas的坐标:鼠标位置 - Canvas左上角位置 + 滚动偏移 const x = e.clientX - rect.left + window.scrollX; const y = e.clientY - rect.top + window.scrollY; ctx.lineTo(x, y); ctx.stroke(); } canvas.addEventListener('mousedown', (e) => { isPainting = true; const rect = canvas.getBoundingClientRect(); const x = e.clientX - rect.left + window.scrollX; const y = e.clientY - rect.top + window.scrollY; ctx.beginPath(); ctx.moveTo(x, y); // 修正:绘制开始时先定位到鼠标起始点 });
3. 调整CSS避免Canvas被意外缩放
给Canvas添加CSS规则,确保显示尺寸与绘图缓冲区一致,避免Elementor默认样式干扰:
#drawing-board { display: block; /* 移除inline元素的默认间距 */ width: 100%; height: 100%; }
完整修正代码
注意:Elementor的HTML元素是嵌入现有页面的,不需要包含html/head/body根标签,直接使用以下代码:
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Manrope&display=swap" rel="stylesheet"> <style> *, *:before, *:after { box-sizing: border-box; } .container{ margin-left: 2em; } .drawing-board{ height: 80vh; /* 用vh替代%,避免父容器高度不确定的问题 */ width: 80%; } #drawing-board { display: block; width: 100%; height: 100%; border: 1px solid #ccc; /* 可选:添加边框方便识别Canvas范围 */ } #toolbar{ display: flex; align-items: center; justify-content: space-around; margin-top: 1em; } input[type="color"]{ -webkit-appearance: none; -moz-appearance: none; appearance: none; width: 70px; height: 70px; background-color: transparent; border: none; cursor: pointer; } input[type="color"]::-webkit-color-swatch{ border-radius: 15px; border: none; } #lineWidth{ visibility: hidden; } #clear{ font-family: 'Manrope', sans-serif; border-radius: 4em; background-color: black; border: solid black 2px; padding: .5em 2em; color: white; cursor: pointer; } #clear:hover{ color: black; background-color: transparent; } </style> <section class="container"> <div class="drawing-board"> <canvas id="drawing-board"></canvas> </div> <div id="toolbar"> <label for="stroke">Choisissez votre couleur : </label> <input id="stroke" name='stroke' type="color" value="#43da86"> <button id="clear">Effacer</button> <input id="lineWidth" name='lineWidth' type="number" value="18"> </div> </section> <script> const canvas = document.getElementById('drawing-board'); const toolbar = document.getElementById('toolbar'); const ctx = canvas.getContext('2d'); let isPainting = false; let lineWidth = 18; // 调整Canvas尺寸 function resizeCanvas() { const rect = canvas.getBoundingClientRect(); canvas.width = rect.width; canvas.height = rect.height; } window.addEventListener('load', resizeCanvas); window.addEventListener('resize', resizeCanvas); toolbar.addEventListener('click', e => { if (e.target.id === 'clear') { ctx.clearRect(0, 0, canvas.width, canvas.height); } }); toolbar.addEventListener('change', e => { if(e.target.id === 'stroke') { ctx.strokeStyle = e.target.value; } if(e.target.id === 'lineWidth') { lineWidth = e.target.value; } }); const draw = (e) => { if(!isPainting) return; ctx.lineWidth = lineWidth; ctx.lineCap = 'round'; const rect = canvas.getBoundingClientRect(); const x = e.clientX - rect.left + window.scrollX; const y = e.clientY - rect.top + window.scrollY; ctx.lineTo(x, y); ctx.stroke(); } canvas.addEventListener('mousedown', (e) => { isPainting = true; const rect = canvas.getBoundingClientRect(); const x = e.clientX - rect.left + window.scrollX; const y = e.clientY - rect.top + window.scrollY; ctx.beginPath(); ctx.moveTo(x, y); }); canvas.addEventListener('mouseup', e => { isPainting = false; ctx.stroke(); ctx.beginPath(); }); canvas.addEventListener('mousemove', draw); </script>
内容的提问来源于stack exchange,提问作者faustyne
相关产品推荐
相关产品推荐

