Windows版Edge中Canvas元素无法删除的问题求助
问题:Windows版Edge中刮刮乐Canvas无法在刮开40%后移除
我用Canvas实现了交互式刮刮乐功能,设定刮开像素占比达到40%时移除Canvas元素。该功能在Chrome、Firefox、Safari及Mac版Edge中均正常运行,但Windows版Edge中Canvas无法被删除。因无Windows设备及Browserstack订阅,无法直接测试。预期效果为刮开至少40%后自动移除Canvas。
可能的问题原因
- Windows Edge对
getImageData的像素值处理存在差异:原代码判断像素红色通道值为0,但Edge中被刮除区域的像素值可能不是严格的0,而是接近0的数值 parentNode.removeChild的DOM操作在Edge中存在延迟或上下文冲突- 鼠标移动时频繁触发移除逻辑,导致Edge中DOM操作异常
解决方案
1. 优化像素判断逻辑
改用Alpha通道判断透明度(而非红色通道),设置阈值替代严格等于0的判断,适配Edge的渲染特性:
function getFilledInPixels(stride) { if (!stride || stride < 1) { stride = 1; } var pixels = ctx.getImageData(0, 0, canvasWidth, canvasHeight), pdata = pixels.data, l = pdata.length, total = (l / stride), count = 0; // 检测Alpha通道,判断像素是否接近完全透明 for (var i = count = 0; i < l; i += stride) { if (pdata[i + 3] < 10) { count++; } } return Math.round((count / total) * 100); }
2. 改用更可靠的DOM移除方法
替换parentNode.removeChild为现代浏览器支持的remove()方法,并添加标记防止重复触发移除操作:
function handlePercentage(filledInPixels) { filledInPixels = filledInPixels || 0; console.log(filledInPixels + '%'); // 添加标记避免重复执行移除逻辑 if (filledInPixels > 40 && !canvas.dataset.removed) { canvas.dataset.removed = 'true'; canvas.remove(); // 移除事件监听,避免内存泄漏 canvas.removeEventListener('mousedown', handleMouseDown); canvas.removeEventListener('touchstart', handleMouseDown); canvas.removeEventListener('mousemove', handleMouseMove); canvas.removeEventListener('touchmove', handleMouseMove); canvas.removeEventListener('mouseup', handleMouseUp); canvas.removeEventListener('touchend', handleMouseUp); } }
3. 调整Canvas绘制上下文设置
将globalCompositeOperation设置移到循环外,减少重复操作,避免Edge渲染异常:
function handleMouseMove(e) { if (!isDrawing) { return; } e.preventDefault(); var currentPoint = getMouse(e, canvas), dist = distanceBetween(lastPoint, currentPoint), angle = angleBetween(lastPoint, currentPoint), x, y; // 提前设置混合模式,避免循环内重复执行 ctx.globalCompositeOperation = 'destination-out'; for (var i = 0; i < dist; i++) { x = lastPoint.x + (Math.sin(angle) * i) - 25; y = lastPoint.y + (Math.cos(angle) * i) - 25; ctx.drawImage(brush, x, y); } lastPoint = currentPoint; handlePercentage(getFilledInPixels(32)); }
4. 确保画笔图片加载完成再绑定事件
原代码未等待画笔图片加载完成就绑定事件,可能导致Edge中绘制异常:
brush.src = 'data:image/png;base64,[Encoded Image Here]'; brush.onload = function() { // 图片加载完成后再绑定交互事件 canvas.addEventListener('mousedown', handleMouseDown, false); canvas.addEventListener('touchstart', handleMouseDown, false); canvas.addEventListener('mousemove', handleMouseMove, false); canvas.addEventListener('touchmove', handleMouseMove, false); canvas.addEventListener('mouseup', handleMouseUp, false); canvas.addEventListener('touchend', handleMouseUp, false); };
修改后的完整JavaScript代码
(function () { 'use strict'; var isDrawing, lastPoint; var container = document.getElementById('js-container'), canvas = document.getElementById('js-canvas'), canvasWidth = canvas.width, canvasHeight = canvas.height, ctx = canvas.getContext('2d'), image = new Image(), brush = new Image(); image.src = 'CanvasImage.png'; image.onload = function () { ctx.drawImage(image, 0, 0); }; brush.src = 'data:image/png;base64,[Encoded Image Here]'; brush.onload = function() { canvas.addEventListener('mousedown', handleMouseDown, false); canvas.addEventListener('touchstart', handleMouseDown, false); canvas.addEventListener('mousemove', handleMouseMove, false); canvas.addEventListener('touchmove', handleMouseMove, false); canvas.addEventListener('mouseup', handleMouseUp, false); canvas.addEventListener('touchend', handleMouseUp, false); }; function distanceBetween(point1, point2) { return Math.sqrt(Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2)); } function angleBetween(point1, point2) { return Math.atan2(point2.x - point1.x, point2.y - point1.y); } function getFilledInPixels(stride) { if (!stride || stride < 1) { stride = 1; } var pixels = ctx.getImageData(0, 0, canvasWidth, canvasHeight), pdata = pixels.data, l = pdata.length, total = (l / stride), count = 0; for (var i = count = 0; i < l; i += stride) { if (pdata[i + 3] < 10) { count++; } } return Math.round((count / total) * 100); } function getMouse(e, canvas) { var offsetX = 0, offsetY = 0, mx, my; if (canvas.offsetParent !== undefined) { do { offsetX += canvas.offsetLeft; offsetY += canvas.offsetTop; } while ((canvas = canvas.offsetParent)); } mx = (e.pageX || e.touches[0].clientX) - offsetX; my = (e.pageY || e.touches[0].clientY) - offsetY; return { x: mx, y: my }; } function handlePercentage(filledInPixels) { filledInPixels = filledInPixels || 0; console.log(filledInPixels + '%'); if (filledInPixels > 40 && !canvas.dataset.removed) { canvas.dataset.removed = 'true'; canvas.remove(); canvas.removeEventListener('mousedown', handleMouseDown); canvas.removeEventListener('touchstart', handleMouseDown); canvas.removeEventListener('mousemove', handleMouseMove); canvas.removeEventListener('touchmove', handleMouseMove); canvas.removeEventListener('mouseup', handleMouseUp); canvas.removeEventListener('touchend', handleMouseUp); } } function handleMouseDown(e) { isDrawing = true; lastPoint = getMouse(e, canvas); } function handleMouseMove(e) { if (!isDrawing) { return; } e.preventDefault(); var currentPoint = getMouse(e, canvas), dist = distanceBetween(lastPoint, currentPoint), angle = angleBetween(lastPoint, currentPoint), x, y; ctx.globalCompositeOperation = 'destination-out'; for (var i = 0; i < dist; i++) { x = lastPoint.x + (Math.sin(angle) * i) - 25; y = lastPoint.y + (Math.cos(angle) * i) - 25; ctx.drawImage(brush, x, y); } lastPoint = currentPoint; handlePercentage(getFilledInPixels(32)); } function handleMouseUp(e) { isDrawing = false; } })();
内容的提问来源于stack exchange,提问作者ST_Kat
相关产品推荐
相关产品推荐

