Kéo có thể điều chỉnh

Trình kéo là một đối tượng điều khiển điều phối thao tác kéo đối tượng có thể kéo để phản hồi các hoạt động tương tác của người dùng.

Có rất ít trường hợp bạn muốn triển khai một trình kéo tuỳ chỉnh, vì bạn không cần tuỳ chỉnh nhiều về việc điều phối thao tác kéo. Trình bổ trợ tuỳ chọn cuộn triển khai một trình kéo tuỳ chỉnh vì trình bổ trợ này muốn thêm tính năng cuộn ở cạnh của không gian làm việc, điều này thay đổi cách toạ độ pixel được chuyển đổi thành toạ độ không gian làm việc.

Yêu cầu của công việc

Trình kéo có một số trách nhiệm khi thực thi thao tác kéo:

  • Gọi các phương thức kéo trên đối tượng có thể kéo.
  • Tính toán vị trí mà đối tượng có thể kéo sẽ di chuyển đến trong toạ độ của không gian làm việc.
  • Gọi các phương thức mục tiêu kéo trên bất kỳ mục tiêu kéo nào được di chuột qua.

Triển khai

Để tạo một trình kéo tuỳ chỉnh, bạn phải triển khai giao diện IDragger.

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

Bạn cũng có thể tạo lớp con cho Blockly.dragging.Dragger tích hợp sẵn, lớp này đã xử lý các trách nhiệm cơ bản.

Bắt đầu kéo

Phương thức onDragStart khởi tạo thao tác kéo. Nó sẽ lưu trữ mọi dữ liệu cần thiết để thực thi thao tác kéo. Phương thức này cũng sẽ gọi startDrag trên đối tượng có thể kéo đang được kéo.

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

  this.draggable.startDrag(e);
}

Phương trình lực cản

Phương thức onDrag thực thi thao tác kéo. Hàm này sẽ tính toán vị trí không gian làm việc mới cho đối tượng có thể kéo dựa trên totalDelta, được cung cấp theo toạ độ pixel.

Thao tác này cũng sẽ cập nhật mọi mục tiêu kéo đang được di chuột qua.

  • Bạn phải luôn gọi wouldDelete trước khi gọi các trình bổ trợ khác trên mục tiêu kéo.
  • Bạn phải luôn gọi onDragExit trên mục tiêu kéo cũ trước khi gọi onDragEnter trên mục tiêu kéo mới.
  • Bạn nên gọi onDragOver sau onDragEnter trong lần đầu tiên mục tiêu kéo được di chuột qua và trên mỗi lệnh gọi bổ sung đến onDrag khi mục tiêu kéo vẫn được di chuột qua.
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;
}

Kết thúc thao tác kéo

Phương thức onEndDrag kết thúc thao tác kéo. Phương thức này sẽ thông báo cho đối tượng có thể kéo rằng thao tác kéo đã kết thúc và mọi mục tiêu kéo được di chuột qua mà đối tượng có thể kéo đã được thả. Phương thức này cũng sẽ loại bỏ đối tượng có thể kéo nếu mục tiêu kéo là một vùng xoá.

  • Bạn phải luôn gọi onDrop trước các phương thức khác.
  • Bạn nên gọi revertDrag nếu mục tiêu kéo ngăn chặn thao tác kéo.
  • Bạn nên gọi endDrag sau khi huỷ thao tác kéo, nhưng trước khi loại bỏ.
  • Bạn nên gọi dispose nếu mục tiêu kéo là một vùng xoá.
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();
  }
}

Đăng ký

Bạn cần đăng ký lớp kéo để có thể tạo lớp này khi phát hiện thao tác kéo.

// 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);

Cách sử dụng

Sau khi triển khai trình kéo tuỳ chỉnh, bạn có thể sử dụng trình kéo đó bằng cách truyền trình kéo đó đến các tuỳ chọn cấu hình.

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,
  },
});