如何为被遮挡的SVG移动元素添加进入/离开区域触发事件?
实现孔洞与移动矩形的区域触发事件
当然可以实现这个需求!我们可以通过矩形碰撞检测来跟踪红色移动矩形(moving_rect)是否进入或离开孔洞(hole)的区域,当状态发生变化时触发对应的属性修改逻辑。下面是具体的实现方案:
核心思路
SVG.js本身没有内置的区域触发事件,所以我们需要:
- 把所有孔洞存入数组,方便统一管理和遍历检测
- 实现一个碰撞检测函数,判断两个矩形是否重叠
- 给每个孔洞标记当前是否被移动矩形覆盖的状态,避免重复触发事件
- 在动画的每一帧(或定期)检查状态变化,触发进入/离开的回调函数
修改后的完整代码
<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
相关产品推荐
相关产品推荐

