Arrastrador

Un objeto de arrastre es un objeto controlador que coordina el arrastre de elementos deslizables en respuesta a las interacciones del usuario.

Hay muy pocas circunstancias en las que querrás implementar un arrastre personalizado, ya que no hay mucho que quieras personalizar sobre la coordinación de un arrastre. El complemento scroll-options implementa un arrastrador personalizado porque quería agregar un desplazamiento en el borde del espacio de trabajo, lo que cambia la forma en que las coordenadas de píxeles se convierten en coordenadas de espacio de trabajo.

Responsabilidades

Tiene varias responsabilidades cuando ejecuta estos elementos:

  • Llamar a métodos de arrastre en el elemento que se puede arrastrar
  • Cálculo de la posición a la que se debe mover el elemento desplazable en las coordenadas del espacio de trabajo
  • Llama a los métodos de destino de arrastre en cualquier objetivo de arrastre que se coloque sobre el cursor.

Implementación

Para crear un arrastre personalizado, debes implementar la interfaz IDragger.

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

También puedes crear una subclase del Blockly.dragging.Dragger integrado, que ya maneja las responsabilidades básicas.

Cómo iniciar arrastres

El método onDragStart inicializa un arrastre. Debe almacenar todos los datos necesarios para ejecutar el arrastre. También debe llamar a startDrag en el elemento que se arrastra.

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

  this.draggable.startDrag(e);
}

Arrastrar

El método onDrag ejecuta un arrastre. Debe calcular la nueva posición del espacio de trabajo para el elemento desplazable según totalDelta, que se proporciona en coordenadas de píxeles.

También debe actualizar los objetivos de arrastre sobre los que se coloca el cursor.

  • Siempre se debe llamar a wouldDelete antes de llamar a otros hooks en el objetivo de arrastre.
  • Siempre se debe llamar a onDragExit en el destino de arrastre anterior antes de llamar a onDragEnter en el nuevo destino de arrastre.
  • Se debe llamar a onDragOver después de onDragEnter la primera vez que se coloca el cursor sobre el objetivo de arrastre y en cada llamada adicional a onDrag, donde aún se coloca el cursor sobre el objetivo de arrastre.
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;
}

Finaliza los arrastres

El método onEndDrag finaliza un arrastre. Debe notificar al elemento desplazable que finalizó el arrastre y a cualquier destino de arrastre sobre el que se colocó el elemento desplazable que se soltó. También debería descartar el elemento desplazable si el objetivo de arrastre es un área de eliminación.

  • Siempre se debe llamar a onDrop antes que a otros métodos.
  • Se debe llamar a revertDrag si el destino de arrastre evita los arrastres.
  • Se debe llamar a endDrag después de revertir el arrastre, pero antes de descartarlo.
  • Se debe llamar a dispose si el objetivo de arrastre es un área de eliminación.
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();
  }
}

Registro

Tu clase de arrastre debe estar registrada para que se pueda crear cuando se detecten los arrastres.

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

Uso

Después de implementar el arrastre personalizado, puedes usarlo pasándolo a tu struct de configuración de inyección.

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