גוררים בהתאמה אישית

גורר הוא אובייקט של בקר שמרכז את משיכת רכיבים שניתן לגרור בתגובה לאינטראקציות של משתמשים.

יש מעט מאוד מקרים שבהם כדאי להטמיע גורם גרירה בהתאמה אישית, כי אין הרבה דברים שתרצו להתאים אישית בנוגע לתיאום של גרירה. התוסף 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 לפני שמפעילים הוקים אחרים ביעד הגרירה.
  • תמיד צריך לקרוא ל-onDragExit על יעד הגרירה הישן לפני שמפעילים את onDragEnter על יעד הגרירה החדש.
  • צריך להפעיל את 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);

שימוש

אחרי שמטמיעים את ה-dragger המותאם אישית, אפשר להעביר אותו לאפשרויות ההגדרה כדי להשתמש בו.

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