自定义 Gizmo 进阶

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

  1. class CustomGizmo extends Editor.Gizmo {
  2. init () {
  3. // 初始化一些参数
  4. }
  5. createGizmoCallBacks () {
  6. // 创建 gizmo 操作回调
  7. // 申明一些局部变量
  8. let startRadius; // 按下鼠标时记录的圆半径
  9. let pressx, pressy; // 按下鼠标时记录的鼠标位置
  10. let updated; // 记录 gizmo 是否被操作过
  11. return {
  12. /**
  13. * 在 gizmo 上按下鼠标时触发
  14. * @property x 按下点的 x 坐标
  15. * @property y 按下点的 y 坐标
  16. * @property event mousedown dom event
  17. */
  18. start: (x, y, event) => {
  19. startRadius = this.target.radius;
  20. pressx = x;
  21. pressy = y;
  22. updated = false;
  23. },
  24. /**
  25. * 在 gizmo 上按下鼠标移动时触发
  26. * @property dx 鼠标移动的 x 位移
  27. * @property dy 鼠标移动的 y 位移
  28. * @property event mousedown dom event
  29. */
  30. update: (dx, dy, event) => {
  31. if (dx === 0 && dy === 0) {
  32. return;
  33. }
  34. updated = true;
  35. // 获取 gizmo 依附的节点
  36. let node = this.node;
  37. // 记录节点信息的 undo 信息,注意参数为节点的 uuid
  38. _Scene.Undo.recordNode( node.uuid );
  39. // 获取 svg view 坐标系下点
  40. let x = pressx + dx, y = pressy + dy;
  41. // 获取节点世界坐标系下点
  42. let pos = this._view.pixelToWorld( cc.v2(x, y) );
  43. // 转换坐标点到节点下
  44. pos = node.convertToNodeSpaceAR(pos);
  45. // 计算 radius
  46. let radius = pos.mag();
  47. // js 在做一些计算后会出现小数位过长的情况, Editor.Math.toPrecision 会帮助做一些小数位的截取
  48. let minDifference = Editor.Math.numOfDecimalsF(1.0/this._view.scale);
  49. this.target.radius = Editor.Math.toPrecision(radius, minDifference);
  50. // 更新 gizmo view
  51. this._view.repaintHost();
  52. },
  53. /**
  54. * 在 gizmo 抬起鼠标时触发
  55. * @property event mousedown dom event
  56. */
  57. end: (event) => {
  58. // 判断是否有操作过 gizmo, 没有则跳过处理
  59. if (updated) {
  60. // 如果 gizmo 有修改需要进入 animation 编辑的属性,需要调用此接口来更新数据
  61. // _Scene.AnimUtils.recordNodeChanged(this.node);
  62. // 推送修改到 undo 下,结束 undo
  63. _Scene.Undo.commit();
  64. }
  65. }
  66. };
  67. }
  68. onCreateRoot () {
  69. // 创建 svg 根节点的回调,可以在这里创建你的 svg 工具
  70. // this._root 可以获取到 Editor.Gizmo 创建的 svg 根节点
  71. // 实例:
  72. // 创建一个 svg 工具
  73. // group 函数文档 : http://documentup.com/wout/svg.js#groups
  74. this._tool = this._root.group();
  75. let circle = this._tool.circle()
  76. // 设置 circle fill 样式
  77. .fill( { color: 'rgba(0,128,255,0.2)' } )
  78. // 设置 circle stroke 样式
  79. .stroke( { color: 'rgba(0,128,255,0.4)', width: 1 } )
  80. // 设置 circle 的点击区域,这里设置的是根据 fill 模式点击
  81. .style( 'pointer-events', 'fill' )
  82. // 设置 circle 鼠标样式
  83. .style( 'cursor', 'pointer' )
  84. ;
  85. // 为 tool 定义一个绘画函数,可以为其他名字
  86. this._tool.plot = (radius, position) => {
  87. this._tool.move(position.x, position.y);
  88. circle.radius(radius);
  89. };
  90. // 创建 gizmo 操作回调函数
  91. let callbacks = this.createGizmoCallBacks();
  92. // 为 tool 添加一个操作回调
  93. // 当在 tool 上按下鼠标时,会创建一个 drag mask
  94. // 如果不需要此辅助函数,可以自行对 tool 注册 mousedown, mousemove, mouseup 来进行操作
  95. Editor.GizmosUtils.addMoveHandles( this._tool, {cursor: 'pointer'}, callbacks );
  96. }
  97. onUpdate () {
  98. // 更新 svg 工具
  99. // 获取 gizmo 依附的组件
  100. let target = this.target;
  101. // 获取 gizmo 依附的节点
  102. let node = this.node;
  103. // 获取组件半径
  104. let radius = target.radius;
  105. // 获取节点世界坐标
  106. let worldPosition = node.convertToWorldSpaceAR(cc.p(0, 0));
  107. // 转换世界坐标到 svg view 上
  108. // svg view 的坐标体系和节点坐标体系不太一样,这里使用内置函数来转换坐标
  109. let viewPosition = this._view.worldToPixel(worldPosition);
  110. // 对齐坐标,防止 svg 因为精度问题产生抖动
  111. let p = Editor.GizmosUtils.snapPixelWihVec2( viewPosition );
  112. // 获取世界坐标下圆半径
  113. let worldPosition2 = node.convertToWorldSpaceAR(cc.p(radius, 0));
  114. let worldRadius = worldPosition.sub(worldPosition2).mag();
  115. worldRadius = Editor.GizmosUtils.snapPixel(worldRadius);
  116. // 移动 svg 工具到坐标
  117. this._tool.plot(worldRadius, p);
  118. }
  119. }
  120. module.exports = CustomGizmo;