Fabric.js组内对象坐标如何转换为屏幕坐标以实现子元素悬停高亮
fabric.js Group子元素相对坐标转屏幕坐标及悬停高亮方案
你要的坐标转换不用手动拆解矩阵计算,fabric.js已经提供了现成的API:
方案1:直接获取子元素画布级绝对坐标(最简单)
所有fabric对象都自带getBoundingRect()方法,组内的子元素调用这个方法返回的结果会自动累加父级Group的偏移、缩放、旋转属性,直接得到相对于画布左上角的绝对坐标,包含left、top、width、height四个属性,直接拿来和鼠标坐标做碰撞检测即可。
你原来的hover方法可以直接修改为:
hover(pointer){ let ctx = this.canvas.getContext("2d") ctx.font = 'caption' let groupMatrix = this.calcTransformMatrix() ctx.clearRect(groupMatrix[4] - 50, groupMatrix[5] -40, 200, 50) ctx.strokeText(`${pointer.x},${pointer.y}`, groupMatrix[4], groupMatrix[5]) this._objects.filter(o => o.type === "LaneParticipant").forEach( lane=> { // 直接获取画布级坐标包围盒 const laneRect = lane.getBoundingRect() const hoverRect = [laneRect.left, laneRect.top, laneRect.width, laneRect.height] ctx.clearRect(hoverRect[0] + 40, hoverRect[1] + 25, 320, 76) ctx.strokeText(String(hoverRect), hoverRect[0] + 50, hoverRect[1] + 50) // 碰撞检测 if(pointer.x >= hoverRect[0] && pointer.x <= hoverRect[0]+hoverRect[2] && pointer.y >= hoverRect[1] && pointer.y <= hoverRect[1]+hoverRect[3]){ ctx.strokeStyle = 'green'; ctx.strokeRect( hoverRect[0], hoverRect[1], hoverRect[2], hoverRect[3] ) ctx.strokeText(String(lane.id), hoverRect[0] + 50, hoverRect[1] + 100) } }) }
方案2:手动转换相对坐标(自定义需求用)
如果你确实需要把组内的任意相对坐标转换为画布坐标,可以用fabric.util.transformPoint结合Group的变换矩阵实现:
// 组内相对坐标,比如你提到的组左上角[-250, -250] const localPoint = new fabric.Point(-250, -250) // 获取Group的画布变换矩阵 const groupMatrix = yourGroup.calcTransformMatrix() // 转换得到画布绝对坐标 const canvasPoint = fabric.util.transformPoint(localPoint, groupMatrix)
关于subTargetCheck不生效的补充说明
你不用自己写碰撞检测逻辑,fabric自带的事件监听就能直接获取悬停的子元素:
- 确保Group的
subTargetCheck属性确实为true(你当前初始化代码里的配置是对的) - 给画布绑定
mouse:move事件,通过事件对象直接拿到子元素:
canvas.on('mouse:move', e => { // 先把所有LaneParticipant的高亮恢复 canvas.getObjects().forEach(obj => { if(obj.type === 'PoolParticipant') { obj.getObjects().forEach(child => { if(child.type === 'LaneParticipant') child.set('stroke', 'transparent') }) } }) // 检测当前悬停的子元素 const target = e.target if(target?.type === 'LaneParticipant') { target.set('stroke', 'green') target.set('strokeWidth', 2) } canvas.requestRenderAll() })
内容的提问来源于stack exchange,提问作者Charlie Benger-Stevenson
相关产品推荐
相关产品推荐

