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

如何为被遮挡的SVG移动元素添加进入/离开区域触发事件?

实现孔洞与移动矩形的区域触发事件

当然可以实现这个需求!我们可以通过矩形碰撞检测来跟踪红色移动矩形(moving_rect)是否进入或离开孔洞(hole)的区域,当状态发生变化时触发对应的属性修改逻辑。下面是具体的实现方案:

核心思路

SVG.js本身没有内置的区域触发事件,所以我们需要:

  1. 把所有孔洞存入数组,方便统一管理和遍历检测
  2. 实现一个碰撞检测函数,判断两个矩形是否重叠
  3. 给每个孔洞标记当前是否被移动矩形覆盖的状态,避免重复触发事件
  4. 在动画的每一帧(或定期)检查状态变化,触发进入/离开的回调函数

修改后的完整代码

<script src="https://cdnjs.cloudflare.com/ajax/libs/svg.js/2.6.5/svg.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- Bootstrap docs: https://getbootstrap.com/docs -->
<div class="container-fluid">
<div class="row">
<div class="col-12">
<h5>Example svg -> click button for animation </h5><button id="mask" class="btn btn-primary">mask rect</button>
<button id="animate" class="btn btn-primary">animate</button>
</div>
</div>
</div>
<div class="container-fluid">
<div class="row">
<div class="col-12">
<div id="myDrawing"></div>
</div>
</div>
</div>
<hr>
svg{
border-style: solid;
border-width: 1px;
}
var draw = SVG('myDrawing').size('100%',200);
var rect_group = draw.group()

// 背景矩形
var background = rect_group.rect(200,150).center(250,100).fill('#000')

// 把所有孔洞存入数组,统一管理
const holes = [
  rect_group.rect(40,40).center(290,70 ).fill('#fff'),
  rect_group.rect(40,40).center(290,130).fill('#fff'),
  rect_group.rect(40,40).center(220,70 ).fill('#fff'),
  rect_group.rect(40,40).center(220,130).fill('#fff')
];

// 给每个孔洞添加初始状态标记:是否被移动矩形覆盖
holes.forEach(hole => hole.isOverlapped = false);

// 移动的红色矩形
var moving_rect = draw.rect(40,40).fill('red').center(250,100)

// 蒙版对象
var mask = draw.mask()

$('#mask').on('click',function(e){
  mask.add(rect_group)
  moving_rect.maskWith(mask)
})

// 检测两个矩形是否重叠的工具函数
function isOverlapping(rectA, rectB) {
  const a = rectA.bbox();
  const b = rectB.bbox();
  // 矩形不重叠的四个条件,取反就是重叠
  return !(a.x + a.width < b.x || a.x > b.x + b.width || a.y + a.height < b.y || a.y > b.y + b.height);
}

// 进入孔洞区域的回调:这里修改填充色为黄色
function onHoleEnter(hole) {
  hole.fill('#ffcc00');
}

// 离开孔洞区域的回调:恢复填充色为白色
function onHoleLeave(hole) {
  hole.fill('#fff');
}

// 检查所有孔洞的重叠状态,触发对应事件
function checkHoleOverlaps() {
  holes.forEach(hole => {
    const currentOverlap = isOverlapping(moving_rect, hole);
    
    // 从非重叠变为重叠:触发进入事件
    if (currentOverlap && !hole.isOverlapped) {
      hole.isOverlapped = true;
      onHoleEnter(hole);
    }
    // 从重叠变为非重叠:触发离开事件
    else if (!currentOverlap && hole.isOverlapped) {
      hole.isOverlapped = false;
      onHoleLeave(hole);
    }
  });
}

$('#animate').on('click',function(e){
  // 在每个动画阶段的每一帧执行检测
  moving_rect
    .animate(250).move(160,40).during(checkHoleOverlaps)
    .animate(250).move(250,40).during(checkHoleOverlaps)
    .animate(250).move(300,80).during(checkHoleOverlaps)
    .animate(250).move(250,160).during(checkHoleOverlaps)
    .animate(250).center(250,100).during(checkHoleOverlaps);
});

关键说明

  • 碰撞检测函数:通过获取两个矩形的边界框(bbox()),判断它们是否存在重叠区域
  • 状态标记:每个孔洞的isOverlapped属性用来记录当前是否被覆盖,确保只有状态变化时才触发回调,避免重复执行
  • 动画帧检测:使用SVG.js动画的during()方法,在动画的每一帧都执行状态检查,保证触发时机的精准性
  • 可扩展性:你可以在onHoleEnter和onHoleLeave函数里修改任何孔洞属性,比如边框、透明度、甚至添加动画效果

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 09:07:24