自定义 Gizmo 进阶

上一篇 讲了如何自定义一个跟随节点移动并缩放的 Gizmo,这篇我们将实现一个可以编辑的 Gizmo

  1. class CustomGizmo extends Editor.Gizmo { init () { // 初始化一些参数 } createGizmoCallBacks () { // 创建 gizmo 操作回调 // 申明一些局部变量 let startRadius; // 按下鼠标时记录的圆半径 let pressx, pressy; // 按下鼠标时记录的鼠标位置 let updated; // 记录 gizmo 是否被操作过 return { /** * 在 gizmo 上按下鼠标时触发 * @property x 按下点的 x 坐标 * @property y 按下点的 y 坐标 * @property event mousedown dom event */ start: (x, y, event) => { startRadius = this.target.radius; pressx = x; pressy = y; updated = false; }, /** * 在 gizmo 上按下鼠标移动时触发 * @property dx 鼠标移动的 x 位移 * @property dy 鼠标移动的 y 位移 * @property event mousedown dom event */ update: (dx, dy, event) => { if (dx === 0 && dy === 0) { return; } updated = true; // 获取 gizmo 依附的节点 let node = this.node; // 记录节点信息的 undo 信息,注意参数为节点的 uuid _Scene.Undo.recordNode( node.uuid ); // 获取 svg view 坐标系下点 let x = pressx + dx, y = pressy + dy; // 获取节点世界坐标系下点 let pos = this._view.pixelToWorld( cc.v2(x, y) ); // 转换坐标点到节点下 pos = node.convertToNodeSpaceAR(pos); // 计算 radius let radius = pos.mag(); // js 在做一些计算后会出现小数位过长的情况, Editor.Math.toPrecision 会帮助做一些小数位的截取 let minDifference = Editor.Math.numOfDecimalsF(1.0/this._view.scale); this.target.radius = Editor.Math.toPrecision(radius, minDifference); // 更新 gizmo view this._view.repaintHost(); }, /** * 在 gizmo 抬起鼠标时触发 * @property event mousedown dom event */ end: (event) => { // 判断是否有操作过 gizmo, 没有则跳过处理 if (updated) { // 如果 gizmo 有修改需要进入 animation 编辑的属性,需要调用此接口来更新数据 // _Scene.AnimUtils.recordNodeChanged(this.node); // 推送修改到 undo 下,结束 undo _Scene.Undo.commit(); } } }; } onCreateRoot () { // 创建 svg 根节点的回调,可以在这里创建你的 svg 工具 // this._root 可以获取到 Editor.Gizmo 创建的 svg 根节点 // 实例: // 创建一个 svg 工具 // group 函数文档 : http://documentup.com/wout/svg.js#groups this._tool = this._root.group(); let circle = this._tool.circle() // 设置 circle fill 样式 .fill( { color: 'rgba(0,128,255,0.2)' } ) // 设置 circle stroke 样式 .stroke( { color: 'rgba(0,128,255,0.4)', width: 1 } ) // 设置 circle 的点击区域,这里设置的是根据 fill 模式点击 .style( 'pointer-events', 'fill' ) // 设置 circle 鼠标样式 .style( 'cursor', 'pointer' ) ; // 为 tool 定义一个绘画函数,可以为其他名字 this._tool.plot = (radius, position) => { this._tool.move(position.x, position.y); circle.radius(radius); }; // 创建 gizmo 操作回调函数 let callbacks = this.createGizmoCallBacks(); // 为 tool 添加一个操作回调 // 当在 tool 上按下鼠标时,会创建一个 drag mask // 如果不需要此辅助函数,可以自行对 tool 注册 mousedown, mousemove, mouseup 来进行操作 Editor.GizmosUtils.addMoveHandles( this._tool, {cursor: 'pointer'}, callbacks ); } onUpdate () { // 更新 svg 工具 // 获取 gizmo 依附的组件 let target = this.target; // 获取 gizmo 依附的节点 let node = this.node; // 获取组件半径 let radius = target.radius; // 获取节点世界坐标 let worldPosition = node.convertToWorldSpaceAR(cc.p(0, 0)); // 转换世界坐标到 svg view 上 // svg view 的坐标体系和节点坐标体系不太一样,这里使用内置函数来转换坐标 let viewPosition = this._view.worldToPixel(worldPosition); // 对齐坐标,防止 svg 因为精度问题产生抖动 let p = Editor.GizmosUtils.snapPixelWihVec2( viewPosition ); // 获取世界坐标下圆半径 let worldPosition2 = node.convertToWorldSpaceAR(cc.p(radius, 0)); let worldRadius = worldPosition.sub(worldPosition2).mag(); worldRadius = Editor.GizmosUtils.snapPixel(worldRadius); // 移动 svg 工具到坐标 this._tool.plot(worldRadius, p); }}module.exports = CustomGizmo;