Draggable

可拖动对象是存在于工作区中的渲染对象,可以对其进行拖放操作。它们实现了 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 元素更改为工作区的拖动层,使其位于任何其他元素的上方。

它还接受一个事件,您可以使用该事件来检查是否按下了键。这样,您就可以(举例来说)在移动时处理拖动操作,其处理方式与正常拖动操作不同。

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 以允许粘贴。

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