big cmap refactoring
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
import {
|
||||
DiagramComponent,
|
||||
pickAttributes,
|
||||
validateOptionalHandler
|
||||
} from "./diagram-component.js";
|
||||
import { DrawingLink, DrawingSurface, DrawingTriple } from "./drawing-core.js";
|
||||
import { DiagramNode } from "./diagram-node.js";
|
||||
|
||||
const LINK_ATTRIBUTES = [
|
||||
"content",
|
||||
"contentType",
|
||||
"cx",
|
||||
"cy",
|
||||
"width",
|
||||
"height",
|
||||
"backgroundColor",
|
||||
"borderColor",
|
||||
"borderWidth",
|
||||
"textColor",
|
||||
"sourceX",
|
||||
"sourceY",
|
||||
"targetX",
|
||||
"targetY",
|
||||
"lineColor",
|
||||
"lineWidth",
|
||||
"hasArrow"
|
||||
];
|
||||
|
||||
/**
|
||||
* Public rendering handle for one diagram link.
|
||||
*
|
||||
* A link owns only visual and interaction state. Its source and target are
|
||||
* DiagramNode instances from the same DiagramEngine.
|
||||
*/
|
||||
export class DiagramLink extends DiagramComponent {
|
||||
constructor(engine, attributes) {
|
||||
const component = new DrawingLink(pickAttributes(attributes, LINK_ATTRIBUTES));
|
||||
super(engine, component, LINK_ATTRIBUTES);
|
||||
}
|
||||
|
||||
/** Read or replace the source node. Pass null to disconnect it. */
|
||||
sourceNode(node) {
|
||||
return this.connectNode(DrawingSurface.CONNECTION_TYPE_SOURCE, node);
|
||||
}
|
||||
|
||||
/** Read or replace the target node. Pass null to disconnect it. */
|
||||
targetNode(node) {
|
||||
return this.connectNode(DrawingSurface.CONNECTION_TYPE_TARGET, node);
|
||||
}
|
||||
|
||||
/** Register a callback for a source or target connection change. */
|
||||
onConnectionChange(handler) {
|
||||
validateOptionalHandler(handler, "connection-change");
|
||||
this.component.connectionChangeHandler = handler ? (type, node, event) => {
|
||||
handler(this, type, node ? this.engine.handleFor(node) : null, event);
|
||||
} : null;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Straighten both link segments between their current endpoints. */
|
||||
straighten() {
|
||||
const relation = this.component.relations()
|
||||
.find((candidate) => candidate instanceof DrawingTriple);
|
||||
const sourceNode = relation ? relation.sourceNode() : null;
|
||||
const targetNode = relation ? relation.targetNode() : null;
|
||||
|
||||
if (!sourceNode || !targetNode) {
|
||||
this.component.straighten();
|
||||
return this;
|
||||
}
|
||||
|
||||
const sourcePoint = relation.connectedPoint(
|
||||
sourceNode, targetNode.cx(), targetNode.cy());
|
||||
const targetPoint = relation.connectedPoint(
|
||||
targetNode, sourceNode.cx(), sourceNode.cy());
|
||||
this.component.straighten(
|
||||
sourcePoint.x, sourcePoint.y, targetPoint.x, targetPoint.y);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Read or update one connected endpoint. */
|
||||
connectNode(type, node) {
|
||||
const connectedComponent = this.engine.drawingSurface
|
||||
.connectedNode(type, this.component);
|
||||
|
||||
if (node === undefined) {
|
||||
return connectedComponent ? this.engine.handleFor(connectedComponent) : null;
|
||||
}
|
||||
|
||||
if (node !== null && !this.validateNode(type, node)) return this;
|
||||
if (connectedComponent) {
|
||||
this.engine.drawingSurface.disconnect(type, connectedComponent, this.component);
|
||||
}
|
||||
if (node !== null) {
|
||||
this.engine.drawingSurface.connect(type, node.component, this.component);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Ensure an endpoint belongs to this engine and is not used at both ends. */
|
||||
validateNode(type, node) {
|
||||
if (!(node instanceof DiagramNode) || node.engine !== this.engine) {
|
||||
throw new TypeError("Invalid diagram node");
|
||||
}
|
||||
|
||||
const otherType = DrawingSurface.anotherConnectionType(type);
|
||||
const otherNode = this.engine.drawingSurface.connectedNode(otherType, this.component);
|
||||
if (otherNode === node.component) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user