自定义可拖动项

可拖动对象是指存在于工作区中且可以拖放的已渲染对象。它们实现了 IDraggable 接口。

在极少数情况下,您可能需要向 Blockly 添加新的可拖动对象(例如,多选插件,或更改现有对象处理拖动的方式),因为您无法向 Blockly 添加新的渲染对象。工作区中唯一可以存在的渲染对象是块、气泡和工作区注释。

职责

在执行拖动操作时,可拖动对象承担着多项责任:

  • 将 SVG 元素移至拖动层
  • 平移 SVG 元素。
  • 触发移动事件

实现

如需创建新的可拖动对象,您必须实现 IRenderedElementIDraggable 接口。这样,Blockly 就会知道您的对象是可见的,并且可以拖动。

class MyDraggable extends IRenderedElement, IDraggable {}

返回根 SVG 元素

getRootSvg 方法会返回根 SVG 元素(通常是一个),其中包含构成可拖动对象的视图的所有其他元素。

getSvgRoot() {
  return this.rootSvg;
}

返回可移动性

isMovable 方法会返回可拖动对象当前是否可移动(因为您可能希望暂时停用对象的拖动功能)。如果 isMovable 返回 false,则改为拖动工作区。

isMovable() {
  return true;
}

返回位置

getRelativeToSurfaceXY 方法会返回一个 Coordinate,用于指定可拖动对象在工作区坐标中的顶部起始角位置。

工作区坐标的原点位于工作区的绝对左侧和绝对顶部。并且在工作区缩放或移动时不会发生变化。

getRelativeToSurfaceXY() {
  return this.loc;
}

开始拖动

startDrag 方法用于初始化可拖动对象上的拖动操作。此方法不会移动可拖动对象。但您应存储完成拖动操作所需的任何数据或构建任何对象。这包括在调用 revertDrag 时需要用于恢复拖动的任何数据。

它还应将 SVG 元素更改为位于工作区的拖动层上,以便它们位于任何其他元素之上。

它还会接收一个事件,您可以使用该事件来检查按下的键。这样一来,您就可以(例如)将按住 Shift 键拖动与正常拖动区别对待。

startDrag(e) {
  // Save the original location so we can revert the drag.
  this.startLoc = this.getRelativeToSurfaceXY();

  // Disable resizing the workspace for performance.
  this.workspace.setResizesEnabled(false);

  // Put the element on the drag layer.
  this.workspace.getLayerManager()?.moveToDragLayer(this);

  // Fire a drag event...

  // etc...
}

拖动

drag 方法实际上会移动可拖动对象。newLoc 位于工作区坐标中,并且还传递了一个事件,您可以使用该事件来检查按下的键。

drag(newLoc, e) {
  this.moveTo(newLoc);
}

还原拖动

revertDrag 方法会将可拖动对象返回到拖动开始时的位置。例如,如果可拖动对象被放置在阻止移动的拖动目标上,就会发生这种情况。

revertDrag() {
  // Move back to the position that was stored in `startDrag`.
  this.moveTo(this.startLoc);
}

结束拖动

endDrag 方法会清理拖动操作,释放所有存储的数据或对象,并将可拖动对象返回到其原始层。

如果调用了 revertDrag,则始终会在 revertDrag 之后调用 endDrag

endDrag() {
  // Put the element back on its original layer (in this case BLOCK).
  this.workspace
    .getLayerManager()
    ?.moveOffDragLayer(this, Blockly.layers.BLOCK);

  // Allow the workspace to start resizing again.
  this.workspace.setResizesEnabled(true);
}

选择

拖动时,被拖动的元素由检测到拖动时选定的元素决定。

ISelectable

如需选择可拖动对象,该对象必须实现 ISelectable 接口。

class MyDraggable implements ISelectable {
  constructor(workspace) {
    this.id = Blockly.utils.idGenerator.genUid();
    this.workspace = workspace;
  }

  select() {
    // Visually indicate this draggable is selected.
  }

  unselect() {
    // Visually indicate this draggable is not selected.
  }
}

设置选择

可以通过调用 Blockly.common.setSelected() 来设置所选元素。通常,您需要响应用户的 pointerdown 事件来执行此操作。

  constructor() {
    this.initSvg();

    Blockly.browserEvents.conditionalBind(
      this.getSvgRoot(),
      'pointerdown',
      this,
      () => Blockly.common.setSelected(this));
  }

兼容性

您的可拖动对象可以实现其他接口,以便与 Blockly 中的其他系统进行交互。

可删除

您可以实现 IDeleteable 接口,以允许垃圾桶或其他删除目标处置可拖动对象。

class MyDraggable implements IDeletable {
  isDeletable() {
    return true;
  }

  dispose() {
    // Dispose of any references to data or SVG elements.
  }

  setDeleteStyle() {
    // Visually indicate that the draggable is about to be deleted.
  }
}

可复制

您可以实现 ICopyable 接口以允许复制可拖动对象,并定义 IPaster 以允许粘贴可拖动对象。

如需详细了解复制粘贴,请参阅复制粘贴