maxGraph/packages/html/stories/PortRefs.stories.js

268 lines
8.1 KiB
JavaScript

/*
Copyright 2021-present The maxGraph project Contributors
Copyright (c) 2006-2020, JGraph Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import {
Graph,
RubberBandHandler,
Point,
EdgeHandler,
ConstraintHandler,
ImageBox,
Shape,
TriangleShape,
constants,
ConnectionConstraint,
Client,
} from '@maxgraph/core';
import {
globalTypes,
globalValues,
rubberBandTypes,
rubberBandValues,
} from './shared/args.js';
// style required by RubberBand
import '@maxgraph/core/css/common.css';
export default {
title: 'Connections/PortRefs',
argTypes: {
...globalTypes,
...rubberBandTypes,
},
args: {
...globalValues,
...rubberBandValues,
},
};
const Template = ({ label, ...args }) => {
Client.setImageBasePath('/images');
const container = document.createElement('div');
container.style.position = 'relative';
container.style.overflow = 'hidden';
container.style.width = `${args.width}px`;
container.style.height = `${args.height}px`;
container.style.background = 'url(/images/grid.gif)';
container.style.cursor = 'default';
// Replaces the port image
ConstraintHandler.prototype.pointImage = new ImageBox('/images/dot.gif', 10, 10);
const graph = new Graph(container);
graph.setConnectable(true);
// Disables automatic handling of ports. This disables the reset of the
// respective style in Graph.cellConnected. Note that this feature may
// be useful if floating and fixed connections are combined.
graph.setPortsEnabled(false);
// Enables rubberband selection
new RubberBandHandler(graph);
// Gets the default parent for inserting new cells. This
// is normally the first child of the root (ie. layer 0).
const parent = graph.getDefaultParent();
// Ports are equal for all shapes...
const ports = [];
// NOTE: Constraint is used later for orthogonal edge routing (currently ignored)
ports.w = { x: 0, y: 0.5, perimeter: true, constraint: 'west' };
ports.e = { x: 1, y: 0.5, perimeter: true, constraint: 'east' };
ports.n = { x: 0.5, y: 0, perimeter: true, constraint: 'north' };
ports.s = { x: 0.5, y: 1, perimeter: true, constraint: 'south' };
ports.nw = { x: 0, y: 0, perimeter: true, constraint: 'north west' };
ports.ne = { x: 1, y: 0, perimeter: true, constraint: 'north east' };
ports.sw = { x: 0, y: 1, perimeter: true, constraint: 'south west' };
ports.se = { x: 1, y: 1, perimeter: true, constraint: 'south east' };
// ... except for triangles
const ports2 = [];
// NOTE: Constraint is used later for orthogonal edge routing (currently ignored)
ports2.in1 = { x: 0, y: 0, perimeter: true, constraint: 'west' };
ports2.in2 = { x: 0, y: 0.25, perimeter: true, constraint: 'west' };
ports2.in3 = { x: 0, y: 0.5, perimeter: true, constraint: 'west' };
ports2.in4 = { x: 0, y: 0.75, perimeter: true, constraint: 'west' };
ports2.in5 = { x: 0, y: 1, perimeter: true, constraint: 'west' };
ports2.out1 = {
x: 0.5,
y: 0,
perimeter: true,
constraint: 'north east',
};
ports2.out2 = { x: 1, y: 0.5, perimeter: true, constraint: 'east' };
ports2.out3 = {
x: 0.5,
y: 1,
perimeter: true,
constraint: 'south east',
};
// Extends shapes classes to return their ports
Shape.prototype.getPorts = function () {
return ports;
};
TriangleShape.prototype.getPorts = function () {
return ports2;
};
const connectionHandler = graph.getPlugin('ConnectionHandler');
// Disables floating connections (only connections via ports allowed)
connectionHandler.isConnectableCell = function (cell) {
return false;
};
EdgeHandler.prototype.isConnectableCell = function (cell) {
return connectionHandler.isConnectableCell(cell);
};
// Disables existing port functionality
graph.view.getTerminalPort = function (state, terminal, source) {
return terminal;
};
// Returns all possible ports for a given terminal
graph.getAllConnectionConstraints = function (terminal, source) {
if (terminal != null && terminal.shape != null && terminal.shape.stencil != null) {
// for stencils with existing constraints...
if (terminal.shape.stencil != null) {
return terminal.shape.stencil.constraints;
}
} else if (terminal != null && terminal.cell.isVertex()) {
if (terminal.shape != null) {
const ports = terminal.shape.getPorts();
const cstrs = [];
for (const id in ports) {
const port = ports[id];
const cstr = new ConnectionConstraint(
new Point(port.x, port.y),
port.perimeter
);
cstr.id = id;
cstrs.push(cstr);
}
return cstrs;
}
}
return null;
};
// Sets the port for the given connection
graph.setConnectionConstraint = function (edge, terminal, source, constraint) {
if (constraint != null) {
const key = source ? 'sourcePort' : 'targetPort';
if (constraint == null || constraint.id == null) {
this.setCellStyles(key, null, [edge]);
} else if (constraint.id != null) {
this.setCellStyles(key, constraint.id, [edge]);
}
}
};
// Returns the port for the given connection
graph.getConnectionConstraint = function (edge, terminal, source) {
const key = source ? 'sourcePort' : 'targetPort';
const id = edge.style[key];
if (id != null) {
const c = new ConnectionConstraint(null, null);
c.id = id;
return c;
}
return null;
};
// Returns the actual point for a port by redirecting the constraint to the port
const graphGetConnectionPoint = graph.getConnectionPoint;
graph.getConnectionPoint = function (vertex, constraint) {
if (constraint.id != null && vertex != null && vertex.shape != null) {
const port = vertex.shape.getPorts()[constraint.id];
if (port != null) {
constraint = new ConnectionConstraint(new Point(port.x, port.y), port.perimeter);
}
}
return graphGetConnectionPoint.apply(this, arguments);
};
// Adds cells to the model in a single step
graph.batchUpdate(() => {
const v1 = graph.insertVertex(parent, null, 'A', 20, 20, 100, 40);
const v2 = graph.insertVertex(parent, null, 'B', 80, 100, 100, 100, {
shape: 'ellipse',
perimeter: 'ellipsePerimeter',
});
const v3 = graph.insertVertex(parent, null, 'C', 190, 30, 100, 60, {
shape: 'triangle',
perimeter: 'trianglePerimeter',
direction: 'south',
});
const e1 = graph.insertEdge(parent, null, '', v1, v2, {
sourcePort: 's',
targetPort: 'nw',
});
const e2 = graph.insertEdge(parent, null, '', v1, v3, {
sourcePort: 'e',
targetPort: 'out3',
});
});
// Comming soon... Integration with orthogonal edge style
// Sets default edge style to use port constraints (needs to be moved up when uncommented)
// graph.getStylesheet().getDefaultEdgeStyle()['edgeStyle'] = 'orthogonalEdgeStyle';
/* let mxUtilsGetPortConstraints = utils.getPortConstraints;
utils.getPortConstraints = function(terminal, edge, source, defaultValue)
{
let key = (source) ? constants.STYLE_SOURCE_PORT : constants.STYLE_TARGET_PORT;
let id = edge.style[key];
let port = terminal.shape.getPorts()[id];
// TODO: Add support for rotation, direction
if (port != null)
{
return port.constraint;
}
return mxUtilsGetPortConstraints.apply(this, arguments);
};
// Connect preview
graph.getPlugin('ConnectionHandler').createEdgeState = function(me)
{
let edge = graph.createEdge(null, null, null, null, null);
return new CellState(this.graph.view, edge, this.graph.getCellStyle(edge));
};
*/
return container;
};
export const Default = Template.bind({});