tracking-code-which-will-go-to-the-HEAD draw/action/Action.js

Source

draw/action/Action.js

/**
 * Represents an interface action.
 */
class Action {
  /**
   * Default constructor.
   * @param {DefaultData} pluginData - Plugin data storage.
   * @param {object} viewport - D3 selection of the view port.
   * @param {DefaultLayout} layout - Layout to organise components.
   */
  constructor(pluginData, viewport, layout) {
    /**
     * Plugin data storage.
     * @type {DefaultData}
     */
    this.pluginData = pluginData;
    /**
     * D3 selection of the view port.
     * @type {object}
     */
    this.viewport = viewport;
    /**
     * Layout to organise components.
     * @type {DefaultLayout}
     */
    this.layout = layout;
  }

  /**
   * Executes the action.
   * @param {object} event - The event triggering the action.
   * @returns {boolean} Indicates whether the scene needs to be redrawn.
   */
  // eslint-disable-next-line no-unused-vars
  execute(event) {
    return false;
  }

  /**
   * Finalizes the action.
   * @param {object} event - The event triggering the action.
   * @returns {boolean} Indicates whether the scene needs to be redrawn.
   */
  // eslint-disable-next-line no-unused-vars
  finalize(event) {
    return false;
  }

  /**
   * Applies the scene transformation based on the plugin data.
   */
  applySceneTransform() {
    const { x, y, zoom } = this.pluginData.scene;
    const translate = `translate(${x} ${y})`;
    const scale = `scale(${zoom})`;

    this.viewport.selectAll('.scene > g').attr('transform', `${translate} ${scale}`);
  }

  /**
   * Gets the source IDs from the event.
   * @param {object} event - The event containing the source information.
   * @returns {string[]} The array of source IDs.
   */
  getSourcesId(event) {
    if (this.pluginData.scene.selection.includes(event.subject.datum().data.id)) {
      return this.pluginData.scene.selection;
    }

    return [event.subject.datum().data.id];
  }

  /**
   * Gets the position of the source.
   * @param {string} sourceId - The ID of the source.
   * @returns {object} The position of the source.
   */
  getSourcePosition(sourceId) {
    const sourceModel = this.viewport.select(`.${sourceId} .model`);

    return {
      x: parseFloat(sourceModel.attr('x')),
      y: parseFloat(sourceModel.attr('y')),
    };
  }

  /**
   * Gets the targets by depth from the event.
   * @param {object} event - The event containing the target information.
   * @returns {string[][]} An array of target IDs grouped by depth.
   */
  getTargetsByDepth(event) {
    const sourceId = event.subject.datum().data.id;
    const {
      clientX: x,
      clientY: y,
    } = event.sourceEvent;
    const targetsByDepth = [];

    this.viewport.selectAll(`g.component.container:not(.${sourceId})`).each((element) => {
      // Can't take x, y, width and height from #element.data.id because, width is growing with
      // component moving.
      const {
        x: eX,
        y: eY,
        width,
        height,
      } = this.viewport.select(`.${element.data.id} .background`)
        .node()
        .getBoundingClientRect();

      if (!(x >= eX && x <= eX + width && y >= eY && y <= eY + height)) {
        return;
      }

      const depth = parseInt(
        this.viewport.select(`.${element.data.id}`).attr('depth'),
        10,
      ) - 1;

      while (targetsByDepth.length <= depth) {
        targetsByDepth.push([]);
      }

      targetsByDepth[depth].push(element.data.id);
    });

    return targetsByDepth;
  }

  /**
   * Gets the target IDs from the event. Ids are ordered by depth, from the deepest to the
   * shallowest.
   * @param {object} event - The event containing the target information.
   * @returns {string[]} An array of target IDs.
   */
  getTargetsId(event) {
    const targetsByDepth = this.getTargetsByDepth(event);

    return targetsByDepth.flat().reverse();
  }

  /**
   * Gets the primary target ID from the event.
   * @param {object} event - The event containing the target information.
   * @returns {string} The primary target ID.
   */
  getTargetId(event) {
    return this.getTargetsId(event)[0];
  }

  /**
   * Gets the transformation between two selectors.
   * @param {string} selector1 - The first selector.
   * @param {string} selector2 - The second selector.
   * @returns {object} The transformation between the two selectors.
   */
  getTransform(selector1, selector2) {
    const {
      x: sourceX,
      y: sourceY,
    } = this.viewport.select(selector1).node().getBoundingClientRect();
    const {
      x: targetX,
      y: targetY,
    } = this.viewport.select(selector2).node().getBoundingClientRect();

    return {
      dx: sourceX - targetX,
      dy: sourceY - targetY,
    };
  }
}

export default Action;