@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
258 lines (190 loc) • 5.93 kB
JavaScript
import { assert } from "../../../assert.js";
import { HashMap } from "../../../collection/map/HashMap.js";
import { Color } from "../../../color/Color.js";
import { BoxLayoutSpec } from "./layout/BoxLayoutSpec.js";
import { ConnectedBoxLayouter } from "./layout/ConnectedBoxLayouter.js";
import { ConnectionEndpointLayoutSpec } from "./layout/ConnectionEndpointLayoutSpec.js";
import { ConnectionLayoutSpec } from "./layout/ConnectionLayoutSpec.js";
import { NodeVisualData } from "./NodeVisualData.js";
export class NodeGraphVisualData {
constructor() {
/**
*
* @type {Map<number, NodeVisualData>}
*/
this.nodes = new Map();
/**
*
* @type {Map<number, Color>}
*/
this.dataColors = new Map();
}
/**
*
* @param {AABB2} result
*/
computeBoundingBox(result) {
this.nodes.forEach(node => {
/**
*
* @type {Rectangle}
*/
const dimensions = node.dimensions;
const p = dimensions.position;
const s = dimensions.size;
result._expandToFit(p.x, p.y, p.x + s.x, p.y + s.y)
});
}
/**
*
* @param {NodeGraph} graph
*/
layout(graph) {
//collect node data
/**
*
* @type {NodeVisualData[]}
*/
const nodes = [];
this.nodes.forEach(v => {
nodes.push(v);
});
const PADDING = 30;
const layouter = new ConnectedBoxLayouter();
/**
*
* @type {ConnectionLayoutSpec[]}
*/
const connections = [];
/**
*
* @type {Map<number, BoxLayoutSpec>}
*/
const node_id_to_box_map = new Map();
/**
*
* @type {BoxLayoutSpec[]}
*/
const boxes = nodes.map(v => {
const d = v.dimensions;
const p = d.position;
const s = d.size;
const box = new BoxLayoutSpec();
box.bounds.set(
p.x - PADDING,
p.y - PADDING,
p.x + s.x + PADDING,
p.y + s.y + PADDING
);
node_id_to_box_map.set(v.id, box);
return box;
});
/**
*
* @type {HashMap<NodeInstancePortReference,ConnectionEndpointLayoutSpec>}
*/
const endpoints = new HashMap();
/**
*
* @param {NodeInstancePortReference} ref
*/
const getEndpointLayoutSpec = (ref) => {
const endpoint = endpoints.get(ref);
if (endpoint !== undefined) {
return endpoint;
} else {
const r = new ConnectionEndpointLayoutSpec();
const id = ref.instance.id;
const node_visual_data = this.getNode(id);
const port_visual_data = node_visual_data.getPort(ref.port.id);
const box = node_id_to_box_map.get(id);
r.box = box;
r.point = port_visual_data.position;
endpoints.set(ref, r);
return r;
}
}
graph.traverseConnections(connection => {
const source = getEndpointLayoutSpec(connection.source);
const target = getEndpointLayoutSpec(connection.target);
const spec = ConnectionLayoutSpec.from(
source,
target
);
source.box.connections.push(spec);
target.box.connections.push(spec);
connections.push(spec);
});
layouter.initialize(boxes, connections);
layouter.layout();
boxes.forEach((box, i) => {
const bounds = box.bounds;
const node = nodes[i];
node.dimensions.position.set(bounds.x0 + PADDING, bounds.y0 + PADDING);
node.dimensions.size.set(bounds.getWidth() - PADDING * 2, bounds.getHeight() - PADDING * 2);
});
}
/**
*
* @param {number} id
* @param {Color} color
*/
addDataColor(id, color) {
assert.isNumber(id, 'id');
this.dataColors.set(id, color);
}
/**
*
* @param {number} id
* @returns {Color}
*/
getDataColor(id) {
return this.dataColors.get(id);
}
/**
*
* @param {number} id
* @param {NodeVisualData} node
*/
addNode(id, node) {
this.nodes.set(id, node);
}
/**
*
* @param {number} id
* @returns {NodeVisualData|undefined}
*/
getNode(id) {
return this.nodes.get(id);
}
toJSON() {
const nodes = {};
for (const [id, node] of this.nodes) {
nodes[id] = node.toJSON()
}
const dataColors = {};
for (const [id, dataColor] of this.dataColors) {
dataColors[id] = dataColor.toJSON();
}
return {
nodes
};
}
fromJSON(json) {
this.nodes.clear();
for (const prop in json.nodes) {
const nodeElement = json.nodes[prop];
const node = new NodeVisualData();
node.fromJSON(nodeElement);
this.nodes.set(node.id, node);
}
this.dataColors.clear();
for (const prop in json.dataColors) {
const id = parseInt(prop);
const jColor = json.dataColors[prop];
const color = new Color();
color.fromJSON(jColor);
this.dataColors.set(id, color);
}
}
}