// Copyright 2022 the V8 project 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 * as C from "./common/constants"; import { GraphPhase, GraphStateType } from "./phases/graph-phase/graph-phase"; import { GraphEdge } from "./phases/graph-phase/graph-edge"; import { GraphNode } from "./phases/graph-phase/graph-node"; import { MovableContainer } from "./movable-container"; export class Graph extends MovableContainer<GraphPhase> { nodeMap: Array<GraphNode>; originNodesMap: Map<string, Array<GraphNode>>; constructor(graphPhase: GraphPhase) { super(graphPhase); this.nodeMap = graphPhase.nodeIdToNodeMap; this.originNodesMap = graphPhase.originIdToNodesMap; } public *nodes(func = (n: GraphNode) => true) { for (const node of this.nodeMap) { if (!node || !func(node)) continue; yield node; } } public *filteredEdges(func: (e: GraphEdge) => boolean) { for (const node of this.nodes()) { for (const edge of node.inputs) { if (func(edge)) yield edge; } } } public forEachEdge(func: (e: GraphEdge) => void) { for (const node of this.nodeMap) { if (!node) continue; for (const edge of node.inputs) { func(edge); } } } public redetermineGraphBoundingBox(showTypes: boolean): [[number, number], [number, number]] { this.minGraphX = 0; this.maxGraphNodeX = 1; this.minGraphY = 0; this.maxGraphY = 1; for (const node of this.nodes()) { if (!node.visible) continue; this.minGraphX = Math.min(this.minGraphX, node.x); this.maxGraphNodeX = Math.max(this.maxGraphNodeX, node.x + node.getWidth()); this.minGraphY = Math.min(this.minGraphY, node.y - C.NODE_INPUT_WIDTH); this.maxGraphY = Math.max(this.maxGraphY, node.y + node.getHeight(showTypes) + C.NODE_INPUT_WIDTH); } this.maxGraphX = this.maxGraphNodeX + this.maxBackEdgeNumber * C.MINIMUM_EDGE_SEPARATION; this.width = this.maxGraphX - this.minGraphX; this.height = this.maxGraphY - this.minGraphY; return [ [this.minGraphX - this.width / 2, this.minGraphY - this.height / 2], [this.maxGraphX + this.width / 2, this.maxGraphY + this.height / 2] ]; } public makeNodeVisible(identifier: string): void { if (this.nodeMap[identifier]) this.nodeMap[identifier].visible = true; } public makeEdgesVisible(): void { if (this.graphPhase.stateType == GraphStateType.NeedToFullRebuild) { this.forEachEdge(edge => edge.visible = edge.source.visible && edge.target.visible ); } else { this.forEachEdge(edge => edge.visible = edge.visible || (this.isRendered() && edge.type === "control" && edge.source.visible && edge.target.visible) ); } } }