Trascinatore

Un elemento di trascinamento è un oggetto controller che coordina il trascinamento dei elementi trascinabili in risposta alle interazioni degli utenti.

Esistono pochissime circostanze in cui è consigliabile implementare un cursore personalizzato, perché non ci sono molti aspetti che è possibile personalizzare per quanto riguarda il coordinamento di uno scorrimento. Il plug-in scroll-options implementa un cursore personalizzato perché voleva aggiungere lo scorrimento all'estremità dell'area di lavoro, il che cambia il modo in cui le coordinate dei pixel vengono convertite in coordinate dell'area di lavoro.

Responsabilità

Il trascinatore ha diverse responsabilità durante l'esecuzione dei trascinamenti:

  • Chiamata dei metodi di trascinamento sull'elemento trascinabile.
  • Calcolo della posizione in cui deve spostarsi l'elemento trascinabile nelle coordinate dell'area di lavoro.
  • Chiamata a metodi di trascinamento su qualsiasi target di trascinamento al passaggio del mouse.

Implementazione

Per creare un cursore personalizzato, devi implementare l'interfaccia IDragger.

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

Puoi anche creare una sottoclasse di Blockly.dragging.Dragger integrato, che gestisce già le responsabilità di base.

Inizia i trascinamenti

Il metodo onDragStart inizializza un trascinamento. Deve memorizzare tutti i dati necessari per eseguire il trascinamento. Dovrebbe anche chiamare startDrag sull'elemento draggable in fase di trascinamento.

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

  this.draggable.startDrag(e);
}

Resistenza aerodinamica

Il metodo onDrag esegue un trascinamento. Dovrebbe calcolare la nuova posizione dell'area di lavoro per l'elemento spostabile in base a totalDelta, che viene fornito in coordinate in pixel.

Dovrebbe anche aggiornare tutti i target di trascinamento su cui viene eseguito il passaggio del mouse.

  • wouldDelete deve essere sempre chiamato prima di chiamare altri hook sul target di trascinamento.
  • onDragExit deve sempre essere chiamato sul vecchio target di trascinamento prima di chiamare onDragEnter sul nuovo target di trascinamento.
  • onDragOver deve essere chiamato dopo onDragEnter la prima volta che il target di trascinamento viene visualizzato e a ogni chiamata aggiuntiva a onDrag in cui il target di trascinamento è ancora visualizzato.
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;
}

Interrompi i trascinamenti

Il metodo onEndDrag termina un trascinamento. L'elemento trascinabile dovrebbe comunicare che il trascinamento è terminato e all'eventuale oggetto di trascinamento su cui è stato passato il mouse che è stato rilasciato. Deve anche eliminare l'elemento spostabile se il target di trascinamento è un'area di eliminazione.

  • onDrop deve sempre essere chiamato prima degli altri metodi.
  • revertDrag deve essere chiamato se il target di trascinamento impedisce i trascinamenti.
  • endDrag deve essere chiamato dopo l'annullamento del trascinamento, ma prima dell'eliminazione.
  • dispose deve essere chiamato se il target di trascinamento è un'area di eliminazione.
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();
  }
}

Registrazione

La classe dragger deve essere registrata in modo che possa essere creata al rilevamento dei trascinamenti.

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

Utilizzo

Dopo aver implementato il cursore personalizzato, puoi utilizzarlo passandolo alla struttura di configurazione dell'iniezione.

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