html canvas 绘图实现可拖拽矩形发生偏移
问题描述
前端在采样canvas 绘制,可拖动矩形时,产生了一个bug,检查了很久找不到原因,请求大佬们解惑;
bug 演示
当图中有两个可拖动块时,拖动一个,另外一个 会发生小许的偏移
完整代码
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>绘制</title> </head> <body> <div style="display: flex"> <div style="width: 200px;margin-top: 100px;margin-right: 20px;margin-left: 10px"> <div draggable="true" id="box" style="width: 200px;height: 50px; background-color: #409eff"></div> </div> <div id="main" style="display: flex;justify-content: center;margin-top: 100px"> </div> </div> <script> let mainCard = document.getElementById("main"); mainCard.ondrop = function(e) { e.preventDefault(); console.log("进入"); let elementById = document.getElementById("main").querySelector("canvas"); let x = e.clientX - elementById.getBoundingClientRect().left; let y = e.clientY - elementById.getBoundingClientRect().top; let { canvas, ctx, image } = canvasData; new CreateBlank(canvas, ctx, { x: x, y: y, width: 200, height: 50, image }); }; mainCard.ondragover = function(e) { e.preventDefault();//解禁当前元素为可放置被拖拽元素的区域,即允许在此放置物体 }; let pathList = []; class CreateBlank { constructor(canvas, ctx, area) { this.ctx = ctx; this.canvas = canvas; this.image = area.image; //创建滑块 this.blob1 = this.createBlob(area.x, area.y, area.width, area.height, "#409eff", 1); //绘制圆滑块 this.DrawBlob(this.blob1); pathList.push(this.blob1); let that = this; //鼠标按下,将鼠标按下坐标保存在x,y中 this.canvas.onmousedown = function(e) { //记录鼠标所在位置的坐标 that.x = e.clientX - that.canvas.getBoundingClientRect().left; that.y = e.clientY - that.canvas.getBoundingClientRect().top; pathList.forEach((res) => { res.InnerWidth = that.x - res.x; res.InnerHeight = that.y - res.y; that.drag(res, that.x, that.y); }); }; } //拖拽函数 drag(blob, x, y) { // 判断鼠标是否在检测区域 let bo = this.getBounds(blob); if (this.containsPoint(bo, x, y)) { let that = this; //注册鼠标移动事件 this.canvas.onmousemove = function(e) { let x = e.clientX - that.canvas.getBoundingClientRect().left; let y = e.clientY - that.canvas.getBoundingClientRect().top; //清除画布内容 that.ctx.clearRect(0, 0, bo.width, bo.height); that.ctx.drawImage(that.image, 0, 0); pathList.forEach(res => { that.DrawBlob(res); if (bo.name === res.name) { //更新块所在的位置 res.x = x - res.InnerWidth; res.y = y - res.InnerHeight; } }); }; //注册鼠标松开事件 this.canvas.onmouseup = function() { this.onmousemove = null; this.onmouseup = null; }; } } //创建圆滑块 createBlob(x, y, width, height, color, alpha) { //定义对象 let blob = {}; blob.alpha = alpha; blob.color = color; blob.x = x; blob.y = y; blob.width = width; blob.height = height; blob.InnerWidth = 0; blob.InnerHeight = 0; blob.name = Symbol("name"); return blob; }; DrawBlob(blob) { this.ctx.globalAlpha = blob.alpha; this.ctx.beginPath(); this.ctx.fillStyle = blob.color; this.ctx.rect(blob.x, blob.y, blob.width, blob.height); this.ctx.fill(); this.ctx.closePath(); this.ctx.globalAlpha = 1; }; //获取检测区域 getBounds(blob) { return { x: blob.x, y: blob.y, width: blob.width, height: blob.height, name: blob.name }; } //判断鼠标是否点击在指定检测区域 containsPoint(rect, x, y) { return !(x < rect.x || x > rect.x + rect.width || y < rect.y || y > rect.y + rect.height); } } function createCanvas(id) { let elementById = document.getElementById(id); return new Promise((resolve, reject) => { let canvas = document.createElement("canvas"); let image = new Image(); image.src = "https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg"; // 如果有缓存,读缓存 image.onload = function() { image.onload = null; // 避免重复加载 canvas.height = image.height; canvas.width = image.width; let ctx = canvas.getContext("2d"); ctx.drawImage(image, 0, 0); elementById.appendChild(canvas); resolve({ canvas, ctx, image }); }; image.onerror = function() { reject(); }; }); } let canvasData = {}; createCanvas("main").then(res => { canvasData = res; }); </script> </body> </html>