ドラガー

ドラガーは、ユーザーの操作に応じてドラッグを調整するコントローラ オブジェクトです。

ドラッグの調整についてカスタマイズする必要があるものはほとんどないため、カスタム ドラッガーを実装する必要がある状況はほとんどありません。scroll-options プラグインは、ワークスペースの端にスクロールを追加することを目的としており、そのためにカスタム ドラッガーを実装しています。これにより、ピクセル座標がワークスペース座標に変換される方法が変更されます。

責任

ドラッグを実行する際に、ドラッグ元にはいくつかの責任があります。

  • ドラッグ可能なオブジェクトでドラッグ メソッドを呼び出す。
  • ドラッグ可能な要素を移動するワークスペース座標の位置を計算します。
  • カーソルを合わせた任意のドラッグ ターゲットでドラッグ ターゲット メソッドを呼び出す。

実装

カスタム ドラッガを作成するには、IDragger インターフェースを実装する必要があります。

class MyDragger implements IDragger {
  // Takes in the draggable being dragged and the workspace the drag
  // is occurring in.
  constructor(draggable, workspace);
}

組み込みの Blockly.dragging.Dragger をサブクラス化することもできます。このクラスは基本的な責任をすでに処理しています。

ドラッグを開始する

onDragStart メソッドはドラッグを初期化します。ドラッグの実行に必要なデータを保存する必要があります。また、ドラッグするドラッグで startDrag を呼び出す必要もあります。

onDragStart(e) {
  this.startLoc = this.draggable.getRelativeToSurfaceXY();

  this.draggable.startDrag(e);
}

抗力

onDrag メソッドはドラッグを実行します。ピクセル座標で指定される totalDelta に基づいて、ドラッグ可能な新しいワークスペースの位置を計算する必要があります。

また、ホバーしているドラッグ ターゲットも更新する必要があります。

  • wouldDelete は、ドラッグ ターゲットで他のフックを呼び出す前に必ず呼び出す必要があります。
  • 新しいドラッグ ターゲットで onDragEnter を呼び出す前に、必ず古いドラッグ ターゲットで onDragExit を呼び出す必要があります。
  • onDragOver は、ドラッグ ターゲットが初めてホバーされたときに onDragEnter の後に呼び出され、ドラッグ ターゲットがまだホバーされている場合に onDrag が呼び出されるたびに呼び出されます。
onDrag(e, totalDelta) {
  // Update the draggable location.
  const delta = this.pixelsToWorkspaceUnits(totalDelta);
  const newLoc = Coordinate.sum(this.startLoc, delta);
  this.draggable.drag(newLoc, e);

  // Call wouldDeleteDraggable.
  if (isDeletable(this.draggable)) {
    this.draggable.setDeleteStyle(
      // Checks that the drag target is an `IDeleteArea` and calls `wouldDelete`
      // on it.
      this.wouldDeleteDraggable(e, this.draggable),
    );
  }

  const newDragTarget = this.workspace.getDragTarget(e);
  if (this.dragTarget !== newDragTarget) {
    // Call `onDragExit` then `onDragEnter`.
    this.dragTarget?.onDragExit(this.draggable);
    newDragTarget?.onDragEnter(this.draggable);
  }
  // Always call `onDragOver`
  newDragTarget?.onDragOver(this.draggable);
  this.dragTarget = newDragTarget;
}

ドラッグを終了する

onEndDrag メソッドはドラッグを終了します。ドラッグ可能関数に、ドラッグが終了したことと、カーソルを合わせたドラッグ ターゲットがドラッグ可能オブジェクトがドロップされたことを通知する必要があります。また、ドラッグ ターゲットが削除領域である場合は、ドラッグ可能な要素を破棄する必要があります。

  • onDrop は、常に他のメソッドの前に呼び出す必要があります。
  • ドラッグ ターゲットがドラッグを禁止する場合は、revertDrag を呼び出す必要があります。
  • endDrag は、ドラッグを元に戻した後、破棄する前に呼び出す必要があります。
  • ドラッグ ターゲットが削除領域の場合は、dispose を呼び出す必要があります。
onDragEnd(e) {
  // Call `onDrop` first.
  const dragTarget = this.workspace.getDragTarget(e);
  if (dragTarget) {
    this.dragTarget?.onDrop(this.draggable);
  }

  // Then revert the drag (if applicable).
  if (this.shouldReturnToStart(e, this.draggable)) {
    this.draggable.revertDrag();
  }

  // Then end the drag.
  this.draggable.endDrag(e);

  // Then delete the draggable (if applicable).
  if (
    isDeletable(this.draggable) &&
    this.wouldDeleteDraggable(e, this.draggable)
  ) {
    this.draggable.dispose();
  }
}

登録

ドラガークラスは、ドラッグが検出されたときに作成されるように、登録する必要があります。

// Note that the type is BLOCK_DRAGGER even though draggers drag more than
// blocks. The name is for backwards compatibility.
Blockly.registry.register(registry.Type.BLOCK_DRAGGER, 'MY_DRAGGER', MyDragger);

用途

実装したカスタム ドラガーは、インジェクション構成構造体に渡すことで使用できます。

const myWorkspace = Blockly.inject('blocklyDiv', {
  plugins: {
    // Note that we pass this to blockDragger even though draggers drag more
    // than blocks. The name is for backwards compatibility.
    blockDragger: MyDragger,
  },
});