All Downloads are FREE. Search and download functionalities are using the official Maven repository.

META-INF.dirigible.dev-tools.web_audio.graph_visualizer.GraphView.js Maven / Gradle / Ivy

There is a newer version: 10.6.27
Show newest version
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import {EdgeTypes, EdgeView, generateEdgePortIdsByData} from './EdgeView.js';
import {NodeCreationData, NodeParamConnectionData, NodeParamDisconnectionData, NodesConnectionData, NodesDisconnectionData, NodesDisconnectionDataWithDestination, ParamCreationData} from './GraphStyle.js';  // eslint-disable-line no-unused-vars
import {NodeLabelGenerator, NodeView} from './NodeView.js';

// A class that tracks all the nodes and edges of an audio graph.
export class GraphView extends Common.Object {
  /**
   * @param {!Protocol.WebAudio.GraphObjectId} contextId
   */
  constructor(contextId) {
    super();

    this.contextId = contextId;

    /** @type {!Map} */
    this._nodes = new Map();
    /** @type {!Map} */
    this._edges = new Map();

    /**
     * For each node ID, keep a set of all out-bound edge IDs.
     * @type {!Platform.Multimap}
     */
    this._outboundEdgeMap = new Platform.Multimap();

    /**
     * For each node ID, keep a set of all in-bound edge IDs.
     * @type {!Platform.Multimap}
     */
    this._inboundEdgeMap = new Platform.Multimap();

    // Use concise node label to replace the long UUID.
    // Each graph has its own label generator so that the label starts from 0.
    this._nodeLabelGenerator = new NodeLabelGenerator();

    /**
     * For each param ID, save its corresponding node Id.
     * @type {!Map}
      */
    this._paramIdToNodeIdMap = new Map();
  }

  /**
   * Add a node to the graph.
   * @param {!NodeCreationData} data
   */
  addNode(data) {
    const label = this._nodeLabelGenerator.generateLabel(data.nodeType);
    const node = new NodeView(data, label);
    this._nodes.set(data.nodeId, node);
    this._notifyShouldRedraw();
  }

  /**
   * Remove a node by id and all related edges.
   * @param {!Protocol.WebAudio.GraphObjectId} nodeId
   */
  removeNode(nodeId) {
    this._outboundEdgeMap.get(nodeId).forEach(edgeId => this._removeEdge(edgeId));
    this._inboundEdgeMap.get(nodeId).forEach(edgeId => this._removeEdge(edgeId));
    this._nodes.delete(nodeId);
    this._notifyShouldRedraw();
  }

  /**
   * Add a param to the node.
   * @param {!ParamCreationData} data
   */
  addParam(data) {
    const node = this.getNodeById(data.nodeId);
    if (!node) {
      console.error('AudioNode should be added before AudioParam');
      return;
    }
    node.addParamPort(data.paramId, data.paramType);
    this._paramIdToNodeIdMap.set(data.paramId, data.nodeId);
    this._notifyShouldRedraw();
  }

  /**
   * Remove a param.
   * @param {!Protocol.WebAudio.GraphObjectId} paramId
   */
  removeParam(paramId) {
    // Only need to delete the entry from the param id to node id map.
    this._paramIdToNodeIdMap.delete(paramId);
    // No need to remove the param port from the node because removeParam will always happen with
    // removeNode(). Since the whole Node will be gone, there is no need to remove port individually.
  }

  /**
   * Add a Node-to-Node connection to the graph.
   * @param {!NodesConnectionData} edgeData
   */
  addNodeToNodeConnection(edgeData) {
    const edge = new EdgeView(edgeData, EdgeTypes.NodeToNode);
    this._addEdge(edge);
  }

  /**
   * Remove a Node-to-Node connection from the graph.
   * @param {!NodesDisconnectionData} edgeData
   */
  removeNodeToNodeConnection(edgeData) {
    if (edgeData.destinationId) {
      // Remove a single edge if destinationId is specified.
      const {edgeId} = generateEdgePortIdsByData(
          /** @type {!NodesDisconnectionDataWithDestination} */ (edgeData), EdgeTypes.NodeToNode);
      this._removeEdge(edgeId);
    } else {
      // Otherwise, remove all outgoing edges from source node.
      this._outboundEdgeMap.get(edgeData.sourceId).forEach(edgeId => this._removeEdge(edgeId));
    }
  }

  /**
   * Add a Node-to-Param connection to the graph.
   * @param {!NodeParamConnectionData} edgeData
   */
  addNodeToParamConnection(edgeData) {
    const edge = new EdgeView(edgeData, EdgeTypes.NodeToParam);
    this._addEdge(edge);
  }

  /**
   * Remove a Node-to-Param connection from the graph.
   * @param {!NodeParamDisconnectionData} edgeData
   */
  removeNodeToParamConnection(edgeData) {
    const {edgeId} = generateEdgePortIdsByData(edgeData, EdgeTypes.NodeToParam);
    this._removeEdge(edgeId);
  }

  /**
   * @param {!Protocol.WebAudio.GraphObjectId} nodeId
   * @return {?NodeView}
   */
  getNodeById(nodeId) {
    return this._nodes.get(nodeId);
  }

  /** @return {!Map} */
  getNodes() {
    return this._nodes;
  }

  /** @return {!Map} */
  getEdges() {
    return this._edges;
  }

  /**
   * @param {!Protocol.WebAudio.GraphObjectId} paramId
   * @return {?Protocol.WebAudio.GraphObjectId}
   */
  getNodeIdByParamId(paramId) {
    return this._paramIdToNodeIdMap.get(paramId);
  }

  /**
   * Add an edge to the graph.
   * @param {!EdgeView} edge
   */
  _addEdge(edge) {
    const sourceId = edge.sourceId;
    // Do nothing if the edge already exists.
    if (this._outboundEdgeMap.hasValue(sourceId, edge.id)) {
      return;
    }

    this._edges.set(edge.id, edge);
    this._outboundEdgeMap.set(sourceId, edge.id);
    this._inboundEdgeMap.set(edge.destinationId, edge.id);

    this._notifyShouldRedraw();
  }

  /**
   * Given an edge id, remove the edge from the graph.
   * Also remove the edge from inbound and outbound edge maps.
   * @param {string} edgeId
   */
  _removeEdge(edgeId) {
    const edge = this._edges.get(edgeId);
    if (!edge) {
      return;
    }

    this._outboundEdgeMap.delete(edge.sourceId, edgeId);
    this._inboundEdgeMap.delete(edge.destinationId, edgeId);

    this._edges.delete(edgeId);
    this._notifyShouldRedraw();
  }

  _notifyShouldRedraw() {
    this.dispatchEventToListeners(Events.ShouldRedraw, this);
  }
}

/** @enum {symbol} */
export const Events = {
  ShouldRedraw: Symbol('ShouldRedraw')
};




© 2015 - 2024 Weber Informatics LLC | Privacy Policy