Thành phần có thể kéo tuỳ chỉnh

Một đối tượng có thể kéo là một đối tượng được kết xuất nằm trong không gian làm việc và có thể được kéo và thả. Chúng triển khai giao diện IDraggable.

Có rất ít trường hợp bạn muốn thêm một đối tượng có thể kéo mới vào Blockly (ví dụ: trình bổ trợ chọn nhiều hoặc thay đổi cách một đối tượng hiện có xử lý thao tác kéo), vì bạn không thể thêm các đối tượng được kết xuất mới vào Blockly. Các đối tượng được kết xuất duy nhất có thể tồn tại trong một không gian làm việc là các khối, bong bóng và bình luận trong không gian làm việc.

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

Các thành phần có thể kéo có một số trách nhiệm khi thực hiện thao tác kéo:

  • Di chuyển các phần tử svg vào lớp kéo.
  • Dịch các phần tử SVG.
  • Kích hoạt sự kiện di chuyển.

Triển khai

Để tạo một đối tượng có thể kéo mới, bạn phải triển khai các giao diện IRenderedElementIDraggable. Điều này cho phép Blockly biết rằng đối tượng của bạn có thể nhìn thấy và có thể kéo.

class MyDraggable extends IRenderedElement, IDraggable {}

Trả về phần tử SVG gốc

Phương thức getRootSvg trả về phần tử svg gốc (thường là một nhóm) chứa tất cả các phần tử khác tạo nên khung hiển thị cho thành phần có thể kéo.

getSvgRoot() {
  return this.rootSvg;
}

Khả năng di chuyển của hàng trả lại

Phương thức isMovable trả về trạng thái có thể di chuyển hiện tại của đối tượng có thể kéo (vì bạn có thể muốn tạm thời tắt tính năng kéo một đối tượng). Nếu isMovable trả về false, thì không gian làm việc sẽ được kéo.

isMovable() {
  return true;
}

Vị trí trả lại

Phương thức getRelativeToSurfaceXY trả về một Coordinate chỉ định vị trí của góc trên cùng bên trái của thành phần có thể kéo trong toạ độ không gian làm việc.

Toạ độ không gian làm việc có điểm gốc ở phía trên cùng và bên trái tuyệt đối của không gian làm việc. Các đường này không thay đổi khi không gian làm việc được thu phóng hoặc di chuyển.

getRelativeToSurfaceXY() {
  return this.loc;
}

Bắt đầu kéo

Phương thức startDrag khởi chạy thao tác kéo trên đối tượng có thể kéo. Phương thức này không di chuyển đối tượng có thể kéo. Nhưng bạn nên lưu trữ mọi dữ liệu hoặc tạo mọi đối tượng cần thiết để hoàn tất thao tác kéo. Điều này bao gồm mọi dữ liệu bạn cần để hoàn nguyên thao tác kéo nếu revertDrag được gọi.

Thao tác này cũng sẽ thay đổi các phần tử svg thành nằm trên lớp kéo của không gian làm việc, vì vậy, chúng sẽ nằm phía trên mọi phần tử khác.

Hàm này cũng nhận một sự kiện mà bạn có thể dùng để kiểm tra các phím đã nhấn. Điều này cho phép bạn (ví dụ: xử lý thao tác kéo trong khi nhấn phím Shift theo cách khác với thao tác kéo thông thường.

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...
}

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

Phương thức drag thực sự di chuyển đối tượng có thể kéo. newLoc nằm trong toạ độ không gian làm việc và cũng có một sự kiện được truyền mà bạn có thể dùng để kiểm tra các phím đã nhấn.

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

Huỷ thao tác kéo

Phương thức revertDrag sẽ trả về đối tượng có thể kéo đến vị trí ban đầu khi bắt đầu thao tác kéo. Điều này xảy ra nếu, chẳng hạn như, thành phần có thể kéo được thả trên một đích kéo ngăn chuyển động.

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

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

Phương thức endDrag dọn dẹp một thao tác kéo, giải phóng mọi dữ liệu hoặc đối tượng đã lưu trữ và trả lại đối tượng có thể kéo về lớp ban đầu.

endDrag luôn được gọi sau revertDrag nếu revertDrag được gọi.

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

Lựa chọn

Phần tử được kéo sẽ do phần tử được chọn khi phát hiện thấy thao tác kéo xác định.

ISelectable

Để được chọn, một đối tượng có thể kéo phải triển khai giao diện 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.
  }
}

Đặt lựa chọn

Bạn có thể đặt phần tử đã chọn bằng cách gọi Blockly.common.setSelected(). thường thì bạn sẽ muốn làm việc này để phản hồi sự kiện pointerdown của người dùng.

  constructor() {
    this.initSvg();

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

Khả năng tương thích

Đối tượng có thể kéo của bạn có thể triển khai các giao diện bổ sung để tương tác với các hệ thống khác trong Blockly.

Có thể xóa

Bạn có thể triển khai giao diện IDeleteable để cho phép thùng rác hoặc các mục tiêu xoá khác loại bỏ thành phần có thể kéo.

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.
  }
}

Có thể sao chép

Bạn có thể triển khai giao diện ICopyable để cho phép sao chép thành phần có thể kéo và xác định IPaster để cho phép dán thành phần đó.

Để biết thêm thông tin về thao tác sao chép và dán, hãy xem phần Sao chép và dán.