StarLightLu 2022-12-07 14:03 采纳率: 50%
浏览 38
已结题

html canvas 绘图实现可拖拽矩形发生偏移

问题描述

在线dome

前端在采样canvas 绘制,可拖动矩形时,产生了一个bug,检查了很久找不到原因,请求大佬们解惑;

bug 演示

当图中有两个可拖动块时,拖动一个,另外一个 会发生小许的偏移

img

完整代码

<!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>

我想要达到的结果

移动另外一个时,原本内容保持原有状态

  • 写回答

1条回答 默认 最新

  • limit、T 2022-12-07 15:38
    关注

    我看不懂你的代码^~^但是改一行代码的位置就可以解决

    img

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录

报告相同问题?

问题事件

  • 系统已结题 12月15日
  • 已采纳回答 12月7日
  • 创建了问题 12月7日

悬赏问题

  • ¥15 centos7.9 IPv6端口telnet和端口监控问题
  • ¥120 计算机网络的新校区组网设计
  • ¥20 完全没有学习过GAN,看了CSDN的一篇文章,里面有代码但是完全不知道如何操作
  • ¥15 使用ue5插件narrative时如何切换关卡也保存叙事任务记录
  • ¥20 海浪数据 南海地区海况数据,波浪数据
  • ¥20 软件测试决策法疑问求解答
  • ¥15 win11 23H2删除推荐的项目,支持注册表等
  • ¥15 matlab 用yalmip搭建模型,cplex求解,线性化处理的方法
  • ¥15 qt6.6.3 基于百度云的语音识别 不会改
  • ¥15 关于#目标检测#的问题:大概就是类似后台自动检测某下架商品的库存,在他监测到该商品上架并且可以购买的瞬间点击立即购买下单