防止画布对象发生碰撞或交叉

2024-02-26

我正在画布上绘制 n 个矩形。矩形是可拖动和可缩放的。 我想防止它们重叠或相交。最好的情况是,如果它们只是相互咬合。

我想办法检查一下十字路口。在我的示例中,我将触摸对象的不透明度设置为 0.1。

巧合的是,在我尝试解决这个问题时,我的对象在接触另一个对象时无法释放。看http://jsfiddle.net/gcollect/jZw7P/ http://jsfiddle.net/gcollect/jZw7P/这是因为第 91 行警报没有执行。alert(math.abs(distx));

实际上这是一种解决方案,但绝对不是一个优雅的解决方案。

有任何想法吗?


这是基于 gco 的答案,已更新以与 FabricJS 1.5.0 配合使用,并进行了以下改进:

  • 形状不重叠。
  • 捕捉更加灵敏。
  • 形状包含在画布内。

JSFiddle:https://jsfiddle.net/aphillips8/31qbr0vn/1/ https://jsfiddle.net/aphillips8/31qbr0vn/1/

var canvas = new fabric.Canvas('canvas'),
canvasWidth = document.getElementById('canvas').width,
canvasHeight = document.getElementById('canvas').height,
counter = 0,
rectLeft = 0,
snap = 20; //Pixels to snap

canvas.selection = false;
plusrect();
plusrect();
plusrect();

function plusrect(top, left, width, height, fill) {
    var rect = new fabric.Rect({
        top: 300,
        name: 'rectangle ' + counter,
        left: 0 + rectLeft,
        width: 100,
        height: 100,
        fill: 'rgba(' + (Math.floor(Math.random() * 256)) + ',' + (Math.floor(Math.random() * 256)) + ',' + (Math.floor(Math.random() * 256)) + ', 0.75)',
        lockRotation: true,
        originX: 'left',
        originY: 'top',
        cornerSize: 15,
        hasRotatingPoint: false,
        perPixelTargetFind: true,
        minScaleLimit: 1,
        maxWidth: canvasWidth,
        maxHeight: canvasHeight
    });

    rect.custom = {};
    rect.custom.counter = counter;

    canvas.add(rect);
    counter++;
    rectLeft += 200;
}

function findNewPos(distX, distY, target, obj) {
    // See whether to focus on X or Y axis
    if(Math.abs(distX) > Math.abs(distY)) {
        if (distX > 0) {
            target.setLeft(obj.getLeft() - target.getWidth());
        } else {
            target.setLeft(obj.getLeft() + obj.getWidth());
        }
    } else {
        if (distY > 0) {
            target.setTop(obj.getTop() - target.getHeight());
        } else {
            target.setTop(obj.getTop() + obj.getHeight());
        }
    }
}

canvas.on('object:moving', function (options) {
    // Sets corner position coordinates based on current angle, width and height
    options.target.setCoords();

    // Don't allow objects off the canvas
    if(options.target.getLeft() < snap) {
        options.target.setLeft(0);
    }

    if(options.target.getTop() < snap) {
        options.target.setTop(0);
    }

    if((options.target.getWidth() + options.target.getLeft()) > (canvasWidth - snap)) {
        options.target.setLeft(canvasWidth - options.target.getWidth());
    }

    if((options.target.getHeight() + options.target.getTop()) > (canvasHeight - snap)) {
        options.target.setTop(canvasHeight - options.target.getHeight());
    }

    // Loop through objects
    canvas.forEachObject(function (obj) {
        if (obj === options.target) return;

        // If objects intersect
        if (options.target.isContainedWithinObject(obj) || options.target.intersectsWithObject(obj) || obj.isContainedWithinObject(options.target)) {

            var distX = ((obj.getLeft() + obj.getWidth()) / 2) - ((options.target.getLeft() + options.target.getWidth()) / 2);
            var distY = ((obj.getTop() + obj.getHeight()) / 2) - ((options.target.getTop() + options.target.getHeight()) / 2);

            // Set new position
            findNewPos(distX, distY, options.target, obj);
        }

        // Snap objects to each other horizontally

        // If bottom points are on same Y axis
        if(Math.abs((options.target.getTop() + options.target.getHeight()) - (obj.getTop() + obj.getHeight())) < snap) {
            // Snap target BL to object BR
            if(Math.abs(options.target.getLeft() - (obj.getLeft() + obj.getWidth())) < snap) {
                options.target.setLeft(obj.getLeft() + obj.getWidth());
                options.target.setTop(obj.getTop() + obj.getHeight() - options.target.getHeight());
            }

            // Snap target BR to object BL
            if(Math.abs((options.target.getLeft() + options.target.getWidth()) - obj.getLeft()) < snap) {
                options.target.setLeft(obj.getLeft() - options.target.getWidth());
                options.target.setTop(obj.getTop() + obj.getHeight() - options.target.getHeight());
            }
        }

        // If top points are on same Y axis
        if(Math.abs(options.target.getTop() - obj.getTop()) < snap) {
            // Snap target TL to object TR
            if(Math.abs(options.target.getLeft() - (obj.getLeft() + obj.getWidth())) < snap) {
                options.target.setLeft(obj.getLeft() + obj.getWidth());
                options.target.setTop(obj.getTop());
            }

            // Snap target TR to object TL
            if(Math.abs((options.target.getLeft() + options.target.getWidth()) - obj.getLeft()) < snap) {
                options.target.setLeft(obj.getLeft() - options.target.getWidth());
                options.target.setTop(obj.getTop());
            }
        }

        // Snap objects to each other vertically

        // If right points are on same X axis
        if(Math.abs((options.target.getLeft() + options.target.getWidth()) - (obj.getLeft() + obj.getWidth())) < snap) {
            // Snap target TR to object BR
            if(Math.abs(options.target.getTop() - (obj.getTop() + obj.getHeight())) < snap) {
                options.target.setLeft(obj.getLeft() + obj.getWidth() - options.target.getWidth());
                options.target.setTop(obj.getTop() + obj.getHeight());
            }

            // Snap target BR to object TR
            if(Math.abs((options.target.getTop() + options.target.getHeight()) - obj.getTop()) < snap) {
                options.target.setLeft(obj.getLeft() + obj.getWidth() - options.target.getWidth());
                options.target.setTop(obj.getTop() - options.target.getHeight());
            }
        }

        // If left points are on same X axis
        if(Math.abs(options.target.getLeft() - obj.getLeft()) < snap) {
            // Snap target TL to object BL
            if(Math.abs(options.target.getTop() - (obj.getTop() + obj.getHeight())) < snap) {
                options.target.setLeft(obj.getLeft());
                options.target.setTop(obj.getTop() + obj.getHeight());
            }

            // Snap target BL to object TL
            if(Math.abs((options.target.getTop() + options.target.getHeight()) - obj.getTop()) < snap) {
                options.target.setLeft(obj.getLeft());
                options.target.setTop(obj.getTop() - options.target.getHeight());
            }
        }
    });

    options.target.setCoords();

    // If objects still overlap

    var outerAreaLeft = null,
    outerAreaTop = null,
    outerAreaRight = null,
    outerAreaBottom = null;

    canvas.forEachObject(function (obj) {
        if (obj === options.target) return;

        if (options.target.isContainedWithinObject(obj) || options.target.intersectsWithObject(obj) || obj.isContainedWithinObject(options.target)) {

            var intersectLeft = null,
            intersectTop = null,
            intersectWidth = null,
            intersectHeight = null,
            intersectSize = null,
            targetLeft = options.target.getLeft(),
            targetRight = targetLeft + options.target.getWidth(),
            targetTop = options.target.getTop(),
            targetBottom = targetTop + options.target.getHeight(),
            objectLeft = obj.getLeft(),
            objectRight = objectLeft + obj.getWidth(),
            objectTop = obj.getTop(),
            objectBottom = objectTop + obj.getHeight();

            // Find intersect information for X axis
            if(targetLeft >= objectLeft && targetLeft <= objectRight) {
                intersectLeft = targetLeft;
                intersectWidth = obj.getWidth() - (intersectLeft - objectLeft);

            } else if(objectLeft >= targetLeft && objectLeft <= targetRight) {
                intersectLeft = objectLeft;
                intersectWidth = options.target.getWidth() - (intersectLeft - targetLeft);
            }

            // Find intersect information for Y axis
            if(targetTop >= objectTop && targetTop <= objectBottom) {
                intersectTop = targetTop;
                intersectHeight = obj.getHeight() - (intersectTop - objectTop);

            } else if(objectTop >= targetTop && objectTop <= targetBottom) {
                intersectTop = objectTop;
                intersectHeight = options.target.getHeight() - (intersectTop - targetTop);
            }

            // Find intersect size (this will be 0 if objects are touching but not overlapping)
            if(intersectWidth > 0 && intersectHeight > 0) {
                intersectSize = intersectWidth * intersectHeight;
            }

            // Set outer snapping area
            if(obj.getLeft() < outerAreaLeft || outerAreaLeft == null) {
                outerAreaLeft = obj.getLeft();
            }

            if(obj.getTop() < outerAreaTop || outerAreaTop == null) {
                outerAreaTop = obj.getTop();
            }

            if((obj.getLeft() + obj.getWidth()) > outerAreaRight || outerAreaRight == null) {
                outerAreaRight = obj.getLeft() + obj.getWidth();
            }

            if((obj.getTop() + obj.getHeight()) > outerAreaBottom || outerAreaBottom == null) {
                outerAreaBottom = obj.getTop() + obj.getHeight();
            }

            // If objects are intersecting, reposition outside all shapes which touch
            if(intersectSize) {
                var distX = (outerAreaRight / 2) - ((options.target.getLeft() + options.target.getWidth()) / 2);
                var distY = (outerAreaBottom / 2) - ((options.target.getTop() + options.target.getHeight()) / 2);

                // Set new position
                findNewPos(distX, distY, options.target, obj);
            }
        }
    });
});
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

防止画布对象发生碰撞或交叉 的相关文章

  • 为什么在缩放的 html5 画布中可以看到伪像?

    我见过this https stackoverflow com questions 7615009 disable interpolation when scaling a canvas and this https stackoverfl
  • CreateJs Canvas 形状在 Windows Phone 上丢失坐标

    我正在制作一个 Createjs 和 html5 项目 在其中绘制一个形状 红色圆圈 当我单击圆圈时它会发出警报 它在所有台式机和 Android 手机上都能正常工作 除非我在 Windows Phone 中打开它 否则它在普通屏幕上工作正
  • html5 canvas 使用图像作为蒙版

    是否可以使用具有形状的图像作为整个画布或画布内图像的蒙版 我想将图像放置在画布中 并在图像上添加蒙版 然后将其另存为新图像 您可以使用 source in globalCompositeOperation 将黑白图像用作蒙版 首先 将蒙版图
  • 为什么盒子大小调整不适用于画布元素上的宽度/高度属性?

    让我们考虑一下这段代码 canvas width 150px height 150px canvas box sizing border box border 5px solid
  • 快速响应的交互式图表/图形:SVG、Canvas 还是其他?

    我正在尝试选择正确的技术来更新一个项目 该项目基本上在可缩放 可平移的图表中渲染数千个点 当前使用 Protovis 的实现性能不佳 在这里查看 http www planethunters org classify http www pl
  • 流媒体性能 - Canvas 与

    我正在开发一个应用程序 需要通过 webSocket 连接以每秒至少 30 帧的速度持续传输图像 我遇到了一些性能问题 并希望尽我所能进行优化 我想知道使用不断更新的图像之间的性能差异是什么 就像这样 img src someDynamic
  • 垂直翻转 Android Canvas

    有没有一种简单的方法可以在 Android 中翻转画布 我似乎找不到任何可以让我垂直翻转它的东西 这样 y 轴上的零就是手机屏幕的底部而不是顶部 如果解决方案不是特别快也没关系 因为我没有对画布进行任何计算密集的操作 提前致谢 Try ca
  • 通过电子邮件发送在 HTML5 画布上创建的图像

    我有一个画布 用户可以通过交互来更改设计 现在 用户完成更改后 可以提交他的设计及其电子邮件 ID 但为了提交设计 我使用以下方法将画布转换为图像http www nihilogic dk labs canvas2image http ww
  • HTML5 画布在缩放和旋转后平移

    我正在尝试用画布做一些事情 首先 我让用户上传图像 如果图像比我想要的大 我需要将其缩小 那部分工作得很好 最近我们遇到了 iPhone 用户上传图像的问题 这些都存在方向问题 我已经弄清楚如何提取方向 我的问题是当我操纵画布中的图像时会发
  • 无法在首页加载时在 Google Chrome 中使用 HTML5 和 getUserMedia() 从网络摄像头拍摄照片

    参考自这篇关于 HTML5Rocks 的文章 http www html5rocks com en tutorials getusermedia intro 我正在尝试构建一个实用程序来从网络摄像头拍照 下面是我的 HTML 代码片段
  • fillRect(0,0,0,1)和clearRect()有什么区别

    之间有什么区别 ctx fillStyle rgba 0 0 0 1 ctx fillRect 0 0 100 100 and ctx clearRect 0 0 100 100 性能或生成的图像或画布数据有什么差异吗 更新以对应有问题的
  • HTML5 使用画布旋转图像

    如何使用画布的 旋转 功能围绕图像中心旋转图像 而不是围绕原点旋转 考虑以下示例
  • Html2canvas 忽略图像的对象拟合

    我一直在尝试利用 html2canvas 来截取元素的屏幕截图 我注意到 div 元素内使用 object fit 属性的图像在 html2canvas 屏幕截图后被拉伸 有没有为此散步 这是我的代码
  • 重命名从 HTML5 画布创建的图像

    我制作了一个简单的画布并将其另存为图像 我在这段代码的帮助下做到了这一点 var canvas document getElementById mycanvas var img canvas toDataURL image png 并弹出创
  • 使用拇指移动变换后的控件会产生奇怪的行为

    当尝试使用拇指在画布上移动控件时 我遇到了奇怪的行为 当我将控件添加到画布并使用 Thumb DragDelta 事件来移动它时 一切看起来都很好 但是 当我对控件应用旋转变换时 拖动它是很奇怪的 控件开始围绕光标旋转 角度越大 圆圈越大
  • 使用 javascript 将 html 文本渲染为位图,无需服务器端代码

    我需要使用 javascript 代码来转换 html 中的文章 帖子 以便最终用户以位图的形式查看 有没有办法在没有服务器端代码的情况下做到这一点 example p testing text here p 您可以使用例如html2can
  • jQuery 生成 div 和碰撞检测

    所以我的学校作业项目快要结束了 我只是错过了两件我似乎无法弄清楚的主要事情 1 如何生成具有随机位置的间隙的管道障碍物 以便鸟可以飞过 尝试使用一个函数来更改间隙位置的管道 div 的 css right attr 并在以下情况下移除管道它
  • 如何以 Rails 形式将图像从 上传到具有 Rails Active Storage 的 S3?

    正如标题中所述 我正在尝试使用 Rails 的 Active Storage 从嵌套在 Rails 表单中的元素将图像上传到我的 S3 存储桶 到目前为止我已经能够使用使用 Active Storage 上传图像 这User class h
  • Python:快速提取大量列表中所有可能的2组合之间的交集

    我有一个大约的数据集 9K 可变长度列表 1 到 100K 元素 我需要计算交集的长度所有可能的 2 列表组合在此数据集中 请注意 每个列表中的元素都是唯一的 因此它们可以在 python 中存储为集合 在 python 中执行此操作最有效
  • Chrome 扩展屏幕截图部分图像裁剪适用于 Retina 显示屏

    我制作了一个 chrome 扩展 它捕获网站的单个元素 div 我使用 chrome tabs gt captureVisibleTab 来制作屏幕截图 然后 使用元素 div 的坐标 x y 和大小 宽度 高度 裁剪屏幕截图 这对我来说在

随机推荐

  • pch 上的 #import 是否会减慢编译时间?

    我正在读这个post http qualitycoding org import order 关于进口 我有一个问题 默认情况下 prefix pch 文件中的 import 是否会减慢编译时间 我应该删除它并仅在必要时导入吗 ifdef
  • 在 NestJS 中使用与 GraphQL 中的输入和对象类型相同的类

    我正在尝试设置我的 graphql resover 来处理对象数组 但无法配置 Args 装饰器 我创建了自己的 ArgsType import ArgsType Field Int ObjectType from nestjs graph
  • 从 github 中删除文件

    我已经在一个项目中使用 github 一段时间了 但是仅作为问题跟踪器 因此 今晚我也花了一些时间来处理代码 并犯了一个菜鸟错误 我提交了凭证文件和其他不必要的数据 我已将它们添加到 gitignore现在提交文件 它们应该不再是问题 但我
  • Docker:如何 Dockerize 并部署 LAMP 应用程序的多个实例

    我需要部署同一 LAMP 或 LEMP 应用程序的多个实例 每个实例都可以通过前端负载均衡器 代理从子域访问 每个实例必须有自己的数据库数据和文件数据 每个实例都可能受到监视 内存限制 CPU 可能会针对每个应用程序实例进行设置 轻松自动部
  • 从 Oracle 存储过程调用 os_command.exec

    我用过os command exec向 Linux shell 发送命令 我正在使用 Oracle 12c 这是一个运行良好的示例代码 select os command exec home smucha app smucha produc
  • Python 3 查找字符串中的最后一个数字

    如何找到任何大字符串中的最后一个数字 例如 在以下字符串中 我想要 47 作为输出 tr bgcolor aa77bb td gt font face verdana color white size 2 gt b gt Total b g
  • WPF Tabcontrol 获取最大选项卡的大小

    我有一个绑定到 Viewmodel 集合的 TabControl 这些 Viewmodel 被转换为适当的值以绘制到选项卡中
  • CosmosDB 存储过程 - Promise 而不是回调

    是否可以在 CosmosDB DocumentDB 存储过程 API 调用中使用 JavaScript Promise 而不是常规回调 一种用法是实现分页 例如 token getToken doSomething token functi
  • Flutter - iOS:命令 /bin/sh 失败,退出代码为 255

    下午好 我尝试在 iOS 上运行一个 Flutter 项目 之前在 Android 上成功运行过 但是 我收到一个错误 x86 64 is not an allowed value for option ios arch Run flutt
  • Delphi 获取 EXE 的句柄

    这是我现在正在做的一个例子 var Client String Handle Integer begin Client Window Name GetWindowThreadProcessId FindWindow nil PAnsiCha
  • 从node.js消息调用Windows API

    我是 Node 新手 我有这个简单的 Node js 服务器可以在 Windows 上运行 服务器代码 var ws require websocket server var server ws createServer server ad
  • 根据原始数据创建队列退出率表

    我需要帮助根据原始数据创建队列退出表 我有一个如下所示的数据集 DT lt data table id c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
  • Chrome扩展-通过后台脚本获取Active Tab的DOM信息

    我知道有很多与这个主题相关的问题 但到目前为止 没有一个问题能让我在 V3 中解决这个问题 当我运行以下background js时 我只得到未定义的结果 我的扩展的目标 至少在这个阶段 是抓取活动选项卡的 DOM 并提取所有 div 元素
  • 如何通过https访问kubernetes服务?

    这是我的集群信息 kubectl cluster info Kubernetes master is running at https 129 146 10 66 6443 Heapster is running at https 129
  • 本地运行 web-Socket 进行调试

    我正在使用 gorilla web socket 我想在本地运行它 我的意思是使用以下 chrome 客户端 或其他推荐的工具 当我进入调试模式时出现错误 I use github com gorilla websocket var upg
  • 如何使用mysql将查询结果存储在变量中

    SET v1 SELECT COUNT FROM user rating SELECT v1 当我执行此查询时set变量显示此错误 Error Code 1064 You have an error in your SQL syntax c
  • 如何简单地扩展 docker-compose 服务并将索引和计数传递给每个服务?

    我正在寻找一种扩展 docker compose 服务的方法并看到了 scale 选项 但找不到任何方法来获取每个容器内的索引和计数 这是一个简化的撰写文件 version 2 1 services my thing restart alw
  • Java OpenCV 绑定

    我正在寻找 OpenCV java 绑定 所有引用都指向处理库 我知道处理是java 但是没有独立的java库吗 或者应该只使用处理库 我刚刚找到了这个 OpenCV 的 java 包装器 https github com bytedeco
  • Visual C++:将传统 C 和 C++ 字符串代码迁移到 Unicode 世界

    我看到 Visual Studio 2008 及更高版本现在开始使用字符集设置为 Unicode 的新解决方案 我的旧 C 代码仅处理英文 ASCII 文本 并且充满了 文字字符串如 Hello World char type char 指
  • 防止画布对象发生碰撞或交叉

    我正在画布上绘制 n 个矩形 矩形是可拖动和可缩放的 我想防止它们重叠或相交 最好的情况是 如果它们只是相互咬合 我想办法检查一下十字路口 在我的示例中 我将触摸对象的不透明度设置为 0 1 巧合的是 在我尝试解决这个问题时 我的对象在接触