FabricJS自定义旋转图标:实现鼠标悬停时切换图标图片
FabricJS自定义旋转图标悬停切换解决方案
直接给图片元素绑定onmouseover事件无效的原因是:FabricJS的旋转图标是通过Canvas API绘制的像素内容,并非真实DOM元素,鼠标事件无法直接绑定到绘制出来的图标上。需要借助FabricJS的画布事件系统,手动检测鼠标是否处于旋转图标区域,再切换图片并重绘。
实现步骤及代码示例
- 提前加载两张状态的图标图片
确保正常状态和悬停状态的图标都加载完成后再进行后续操作,避免绘制时图片未就绪:
// 封装图片加载Promise function loadImage(src) { return new Promise((resolve, reject) => { const img = new Image(); img.onload = () => resolve(img); img.onerror = reject; img.src = src; }); } // 声明全局变量存储两张图标 let rotationIconNormal, rotationIconHover; // 标记当前是否悬停在旋转图标上 let isRotationIconHovered = false; // 批量加载图标 Promise.all([ loadImage("LibraryTrans.png"), // 正常状态图标路径 loadImage("LibraryHoverTrans.png") // 悬停状态图标路径 ]).then(([normal, hover]) => { rotationIconNormal = normal; rotationIconHover = hover; // 加载完成后初始化Canvas并设置自定义旋转图标 initCanvas(); });
- 初始化Canvas并绑定鼠标移动事件
在鼠标移动时,检测当前选中对象的旋转图标区域是否包含鼠标指针:
function initCanvas() { const canvas = new fabric.Canvas('your-canvas-id'); // 绑定鼠标移动事件 canvas.on('mouse:move', (options) => { if (!options.target) { // 无选中对象时重置悬停状态 if (isRotationIconHovered) { isRotationIconHovered = false; canvas.renderAll(); } return; } const target = options.target; const pointer = canvas.getPointer(options.e); const cornerSize = canvas.cornerSize; // 计算旋转图标的实际位置(考虑对象旋转后的坐标) const rotationPoint = target.getRotatedPoint( new fabric.Point(target.left + target.width / 2, target.top), target.angle ); // 创建临时矩形模拟旋转图标的点击区域 const hoverArea = new fabric.Rect({ left: rotationPoint.x - cornerSize / 2, top: rotationPoint.y - cornerSize / 2, width: cornerSize, height: cornerSize, angle: target.angle }); // 更新悬停状态,状态变化时触发重绘 const wasHovered = isRotationIconHovered; isRotationIconHovered = hoverArea.containsPoint(pointer); if (wasHovered !== isRotationIconHovered) { canvas.renderAll(); } }); // 设置自定义旋转图标渲染函数 canvas.controlsUtils.renderRotationIcon = renderRotationIcon; }
- 修改自定义渲染函数,根据状态切换图片
在绘制旋转图标时,根据isRotationIconHovered状态选择对应的图片:
function renderRotationIcon(ctx, left, top, styleOverride, fabricObject) { const size = this.cornerSize; ctx.save(); ctx.translate(left, top); ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle)); // 根据悬停状态选择要绘制的图标 const currentIcon = isRotationIconHovered ? rotationIconHover : rotationIconNormal; ctx.drawImage(currentIcon, -size / 2, -size / 2, size, size); ctx.restore(); }
补充说明
- 如果你的旋转图标位置不是默认的顶部中间,需要调整
rotationPoint的计算逻辑,对应你自定义的旋转角位置。 - 若使用TypeScript,需要给相关变量添加类型声明,或者保留原代码中的
//@ts-ignore注释。
内容的提问来源于stack exchange,提问作者Alien13
相关产品推荐
相关产品推荐

