You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

学校项目:拖拽Div元素至桌游终点时触发Modal弹窗的实现方法

解决Fabric.js拖拽元素到终点触发Modal的问题

嘿,看起来你已经把Fabric.js的拖拽网格对齐搞定了,接下来要实现“拖拽到终点触发弹窗”其实很简单,咱们一步步来:

1. 先定义你的终点区域

首先得明确“终点线”对应的坐标范围,比如假设你的终点是画布左上角一块区域(你可以根据实际需求调整数值):

// 定义终点区域:x从0到150,y从0到400的矩形
const endZone = {
  left: 0,
  top: 0,
  width: 150,
  height: 400
};

2. 监听拖拽结束事件

你现在用的object:moving是拖拽过程中实时触发的,咱们应该用object:modified事件——这个事件会在用户结束拖拽(松开鼠标)时触发,更适合做终点判断。

3. 实现位置判断与Modal触发逻辑

在事件回调里,我们需要检查被拖拽的图片是否进入了终点区域,这里用“元素中心是否在终点内”的判断逻辑,下面是完整的代码修改:

var canvas = new fabric.Canvas('c', { selection: false });
var grid = 35;
// 定义终点区域(根据你的实际需求调整)
const endZone = {
  left: 0,
  top: 0,
  width: 150,
  height: 400
};

// 创建网格(你的原有代码,保持不变)
for (var i = 0; i < (3000 / grid); i++) {
 canvas.add(new fabric.Line([ i * grid, 0, i * grid, 3000], { stroke: '#ccc', selectable: false }));
 canvas.add(new fabric.Line([ 0, i * grid, 3000, i * grid], { stroke: '#ccc', selectable: false }))
}

// 图片加载部分(优化了重复代码)
const busUrls = [
  'https://oege.ie.hva.nl/~delawai/assets/images/Photos/bus_geel.png',
  'https://oege.ie.hva.nl/~delawai/assets/images/Photos/bus_blauw.png',
  'https://oege.ie.hva.nl/~delawai/assets/images/Photos/bus_lichtblauw.png',
  'https://oege.ie.hva.nl/~delawai/assets/images/Photos/bus_lichtgroen.png',
  'https://oege.ie.hva.nl/~delawai/assets/images/Photos/bus_paars.png',
  'https://oege.ie.hva.nl/~delawai/assets/images/Photos/bus_rood.png',
  'https://oege.ie.hva.nl/~delawai/assets/images/Photos/bus_roze.png'
];

// 封装图片加载逻辑,减少重复代码
function loadBusImage(imgUrl, posTop) {
  fabric.Image.fromURL(imgUrl, (img) => {
    const width = 100;
    const height = 80;
    const widthFactor = width / img.width;
    const heightFactor = height/ img.height;
    const minFactor = Math.min(widthFactor, heightFactor);
    img.scale(minFactor);
    canvas.add(img)
  }, {
    left: 1790,
    top: posTop,
  });
}

// 批量加载所有巴士图片
busUrls.forEach((url, index) => {
  loadBusImage(url, 40 + index * 60);
});

// 网格对齐逻辑(原有代码,保持不变)
canvas.on('object:moving', function(options) {
 options.target.set({
 left: Math.round(options.target.left / grid) * grid,
 top: Math.round(options.target.top / grid) * grid
 });
});

// 新增:拖拽结束后检查是否到达终点
canvas.on('object:modified', function(options) {
  const obj = options.target;
  // 跳过已经触发过弹窗的元素,防止重复触发
  if (obj.reachedEnd) return;

  // 获取元素的中心坐标
  const objCenterX = obj.left + obj.width * obj.scaleX / 2;
  const objCenterY = obj.top + obj.height * obj.scaleY / 2;

  // 判断中心是否在终点区域内
  const isInEndZone = 
    objCenterX >= endZone.left && 
    objCenterX <= endZone.left + endZone.width &&
    objCenterY >= endZone.top && 
    objCenterY <= endZone.top + endZone.height;

  if (isInEndZone) {
    // 标记元素已到达终点
    obj.set('reachedEnd', true);
    
    // 触发Modal弹窗,这里用原生JS示例,你可以换成自己的Modal组件(比如Bootstrap Modal)
    const modal = document.createElement('div');
    modal.style.cssText = `
      position: fixed;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      padding: 20px;
      background: white;
      border-radius: 8px;
      border: 1px solid #ccc;
      z-index: 9999;
      box-shadow: 0 0 15px rgba(0,0,0,0.2);
    `;
    modal.innerHTML = `
      <h3>🎉 到达终点!</h3>
      <p>你成功把巴士开到终点啦!</p>
      <button style="margin-top:10px;padding:8px 16px;cursor:pointer;" onclick="this.parentElement.remove()">关闭</button>
    `;
    document.body.appendChild(modal);
  }
});

关键说明:

  • 终点区域自定义:你可以根据桌游的实际布局调整endZone的参数,比如如果终点是一条垂直的线(比如x=100),可以把判断逻辑改成obj.left <= 100。
  • Modal替换:示例里用了原生JS创建弹窗,如果你用的是Vue/React框架或者Bootstrap这类UI库,直接调用对应的Modal组件即可。
  • 重复触发防护:通过给元素添加reachedEnd属性,避免同一个巴士多次触发弹窗。

内容的提问来源于stack exchange,提问作者Mark

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:04:47