@joint/core 4.2.0-alpha.1 → 4.2.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/geometry.js +1 -1
- package/dist/geometry.min.js +2 -3
- package/dist/joint.d.ts +321 -55
- package/dist/joint.js +2499 -853
- package/dist/joint.min.js +2 -3
- package/dist/joint.nowrap.js +2499 -853
- package/dist/joint.nowrap.min.js +2 -3
- package/dist/vectorizer.js +1 -1
- package/dist/vectorizer.min.js +2 -3
- package/dist/version.mjs +1 -1
- package/package.json +12 -9
- package/src/config/index.mjs +3 -1
- package/src/dia/Cell.mjs +77 -80
- package/src/dia/CellCollection.mjs +136 -0
- package/src/dia/CellView.mjs +1 -2
- package/src/dia/Element.mjs +2 -3
- package/src/dia/Graph.mjs +610 -317
- package/src/dia/GraphLayer.mjs +53 -0
- package/src/dia/GraphLayerCollection.mjs +313 -0
- package/src/dia/GraphLayerView.mjs +128 -0
- package/src/dia/GraphLayersController.mjs +166 -0
- package/src/dia/GraphTopologyIndex.mjs +222 -0
- package/src/dia/{layers/GridLayer.mjs → GridLayerView.mjs} +23 -16
- package/src/dia/{PaperLayer.mjs → LayerView.mjs} +52 -17
- package/src/dia/LegacyGraphLayerView.mjs +14 -0
- package/src/dia/Paper.mjs +756 -423
- package/src/dia/ToolsView.mjs +3 -3
- package/src/dia/index.mjs +6 -1
- package/src/dia/ports.mjs +11 -2
- package/src/dia/symbols.mjs +24 -0
- package/src/mvc/Collection.mjs +19 -19
- package/src/mvc/Model.mjs +13 -10
- package/types/joint.d.ts +320 -54
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { isEmpty } from '../util/index.mjs';
|
|
2
|
+
import { Listener } from '../mvc/Listener.mjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @class GraphTopologyIndex
|
|
6
|
+
* @description Maintains an index of the graph topology (adjacency list)
|
|
7
|
+
* for fast graph queries.
|
|
8
|
+
*/
|
|
9
|
+
export class GraphTopologyIndex extends Listener {
|
|
10
|
+
|
|
11
|
+
constructor(options) {
|
|
12
|
+
super(options);
|
|
13
|
+
|
|
14
|
+
// Make sure there are no arguments passed to the callbacks.
|
|
15
|
+
// See the `mvc.Listener` documentation for more details.
|
|
16
|
+
this.callbackArguments = [];
|
|
17
|
+
|
|
18
|
+
this.layerCollection = options.layerCollection;
|
|
19
|
+
if (!this.layerCollection) {
|
|
20
|
+
throw new Error('GraphTopologyIndex: "layerCollection" option is required.');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
this.initializeIndex();
|
|
24
|
+
this.startListening();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @public
|
|
29
|
+
* @description Start listening to graph and layer collection events
|
|
30
|
+
* to maintain the topology index.
|
|
31
|
+
*/
|
|
32
|
+
startListening() {
|
|
33
|
+
this.listenTo(this.layerCollection.graph, {
|
|
34
|
+
'add': this._restructureOnAdd,
|
|
35
|
+
'remove': this._restructureOnRemove,
|
|
36
|
+
'reset': this._restructureOnReset
|
|
37
|
+
});
|
|
38
|
+
// Listening to the collection instead of the graph
|
|
39
|
+
// to avoid reacting to graph attribute change events
|
|
40
|
+
// e.g. graph.set('source', ...);
|
|
41
|
+
this.listenTo(this.layerCollection, {
|
|
42
|
+
'change:source': this._restructureOnChangeSource,
|
|
43
|
+
'change:target': this._restructureOnChangeTarget
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @protected
|
|
49
|
+
* @description Initialize the internal data structures.
|
|
50
|
+
*/
|
|
51
|
+
initializeIndex() {
|
|
52
|
+
// Outgoing edges per node. Note that we use a hash-table for the list
|
|
53
|
+
// of outgoing edges for a faster lookup.
|
|
54
|
+
// [nodeId] -> Object [edgeId] -> true
|
|
55
|
+
this._out = {};
|
|
56
|
+
// Ingoing edges per node.
|
|
57
|
+
// [nodeId] -> Object [edgeId] -> true
|
|
58
|
+
this._in = {};
|
|
59
|
+
// `_nodes` is useful for quick lookup of all the elements in the graph, without
|
|
60
|
+
// having to go through the whole cells array.
|
|
61
|
+
// [node ID] -> true
|
|
62
|
+
this._nodes = {};
|
|
63
|
+
// `_edges` is useful for quick lookup of all the links in the graph, without
|
|
64
|
+
// having to go through the whole cells array.
|
|
65
|
+
// [edgeId] -> true
|
|
66
|
+
this._edges = {};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @protected
|
|
71
|
+
* @description Restructure the topology index on graph reset.
|
|
72
|
+
* E.g. when fromJSON or resetCells is called.
|
|
73
|
+
*/
|
|
74
|
+
_restructureOnReset() {
|
|
75
|
+
this.initializeIndex();
|
|
76
|
+
this.layerCollection.getCells().forEach(this._restructureOnAdd, this);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @protected
|
|
81
|
+
* @description Restructure the topology index on cell addition.
|
|
82
|
+
* @param {dia.Cell} cell - The cell being added.
|
|
83
|
+
*/
|
|
84
|
+
_restructureOnAdd(cell) {
|
|
85
|
+
if (cell.isLink()) {
|
|
86
|
+
this._edges[cell.id] = true;
|
|
87
|
+
const { source, target } = cell.attributes;
|
|
88
|
+
if (source.id) {
|
|
89
|
+
(this._out[source.id] || (this._out[source.id] = {}))[cell.id] = true;
|
|
90
|
+
}
|
|
91
|
+
if (target.id) {
|
|
92
|
+
(this._in[target.id] || (this._in[target.id] = {}))[cell.id] = true;
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
this._nodes[cell.id] = true;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* @protected
|
|
101
|
+
* @description Restructure the topology index on cell removal.
|
|
102
|
+
* @param {dia.Cell} cell - The cell being removed.
|
|
103
|
+
*/
|
|
104
|
+
_restructureOnRemove(cell) {
|
|
105
|
+
if (cell.isLink()) {
|
|
106
|
+
delete this._edges[cell.id];
|
|
107
|
+
const { source, target } = cell.attributes;
|
|
108
|
+
if (source.id && this._out[source.id] && this._out[source.id][cell.id]) {
|
|
109
|
+
delete this._out[source.id][cell.id];
|
|
110
|
+
}
|
|
111
|
+
if (target.id && this._in[target.id] && this._in[target.id][cell.id]) {
|
|
112
|
+
delete this._in[target.id][cell.id];
|
|
113
|
+
}
|
|
114
|
+
} else {
|
|
115
|
+
delete this._nodes[cell.id];
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* @protected
|
|
121
|
+
* @description Restructure the topology index on link source change.
|
|
122
|
+
* @param {dia.Link} link - The link being changed.
|
|
123
|
+
*/
|
|
124
|
+
_restructureOnChangeSource(link) {
|
|
125
|
+
|
|
126
|
+
const prevSource = link.previous('source');
|
|
127
|
+
if (prevSource.id && this._out[prevSource.id]) {
|
|
128
|
+
delete this._out[prevSource.id][link.id];
|
|
129
|
+
}
|
|
130
|
+
const source = link.attributes.source;
|
|
131
|
+
if (source.id) {
|
|
132
|
+
(this._out[source.id] || (this._out[source.id] = {}))[link.id] = true;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* @protected
|
|
138
|
+
* @description Restructure the topology index on link target change.
|
|
139
|
+
* @param {dia.Link} link - The link being changed.
|
|
140
|
+
*/
|
|
141
|
+
_restructureOnChangeTarget(link) {
|
|
142
|
+
|
|
143
|
+
const prevTarget = link.previous('target');
|
|
144
|
+
if (prevTarget.id && this._in[prevTarget.id]) {
|
|
145
|
+
delete this._in[prevTarget.id][link.id];
|
|
146
|
+
}
|
|
147
|
+
const target = link.get('target');
|
|
148
|
+
if (target.id) {
|
|
149
|
+
(this._in[target.id] || (this._in[target.id] = {}))[link.id] = true;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* @public
|
|
155
|
+
* @description Get all outbound edges for the node. Time complexity: O(1).
|
|
156
|
+
* @param {string} nodeId - The id of the node.
|
|
157
|
+
* @returns {Object} - An object of the form: [edgeId] -> true.
|
|
158
|
+
*/
|
|
159
|
+
getOutboundEdges(nodeId) {
|
|
160
|
+
return this._out[nodeId] || {};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* @public
|
|
165
|
+
* @description Get all inbound edges for the node. Time complexity: O(1).
|
|
166
|
+
* @param {string} nodeId - The id of the node.
|
|
167
|
+
* @returns {Object} - An object of the form: [edgeId] -> true.
|
|
168
|
+
*/
|
|
169
|
+
getInboundEdges(nodeId) {
|
|
170
|
+
return this._in[nodeId] || {};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* @public
|
|
175
|
+
* @description Get all sink nodes (leafs) in the graph. Time complexity: O(|V|).
|
|
176
|
+
* @returns {string[]} - Array of node ids.
|
|
177
|
+
*/
|
|
178
|
+
getSinkNodes() {
|
|
179
|
+
const sinks = [];
|
|
180
|
+
for (const nodeId in this._nodes) {
|
|
181
|
+
if (!this._out[nodeId] || isEmpty(this._out[nodeId])) {
|
|
182
|
+
sinks.push(nodeId);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return sinks;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* @public
|
|
190
|
+
* @description Get all source nodes (roots) in the graph. Time complexity: O(|V|).
|
|
191
|
+
* @returns {string[]} - Array of node ids.
|
|
192
|
+
*/
|
|
193
|
+
getSourceNodes() {
|
|
194
|
+
const sources = [];
|
|
195
|
+
for (const nodeId in this._nodes) {
|
|
196
|
+
if (!this._in[nodeId] || isEmpty(this._in[nodeId])) {
|
|
197
|
+
sources.push(nodeId);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return sources;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* @public
|
|
205
|
+
* @description Return `true` if `nodeId` is a source node (root). Time complexity: O(1).
|
|
206
|
+
* @param {string} nodeId - The id of the node to check.
|
|
207
|
+
* @returns {boolean}
|
|
208
|
+
*/
|
|
209
|
+
isSourceNode(nodeId) {
|
|
210
|
+
return !this._in[nodeId] || isEmpty(this._in[nodeId]);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* @public
|
|
215
|
+
* @description Return `true` if `nodeId` is a sink node (leaf). Time complexity: O(1).
|
|
216
|
+
* @param {string} nodeId - The id of the node to check.
|
|
217
|
+
* @returns {boolean}
|
|
218
|
+
*/
|
|
219
|
+
isSinkNode(nodeId) {
|
|
220
|
+
return !this._out[nodeId] || isEmpty(this._out[nodeId]);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { LayerView } from './LayerView.mjs';
|
|
2
2
|
import {
|
|
3
3
|
isFunction,
|
|
4
4
|
isString,
|
|
@@ -6,10 +6,10 @@ import {
|
|
|
6
6
|
omit,
|
|
7
7
|
assign,
|
|
8
8
|
merge,
|
|
9
|
-
} from '
|
|
10
|
-
import V from '
|
|
9
|
+
} from '../util/index.mjs';
|
|
10
|
+
import V from '../V/index.mjs';
|
|
11
11
|
|
|
12
|
-
export const
|
|
12
|
+
export const GridLayerView = LayerView.extend({
|
|
13
13
|
|
|
14
14
|
style: {
|
|
15
15
|
'pointer-events': 'none'
|
|
@@ -19,13 +19,20 @@ export const GridLayer = PaperLayer.extend({
|
|
|
19
19
|
_gridSettings: null,
|
|
20
20
|
|
|
21
21
|
init() {
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
LayerView.prototype.init.apply(this, arguments);
|
|
23
|
+
this.paper = this.options.paper;
|
|
24
24
|
this._gridCache = null;
|
|
25
25
|
this._gridSettings = [];
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
afterPaperReferenceSet(paper) {
|
|
26
29
|
this.listenTo(paper, 'transform resize', this.updateGrid);
|
|
27
30
|
},
|
|
28
31
|
|
|
32
|
+
beforePaperReferenceUnset(paper) {
|
|
33
|
+
this.stopListening(paper);
|
|
34
|
+
},
|
|
35
|
+
|
|
29
36
|
setGrid(drawGrid) {
|
|
30
37
|
this._gridSettings = this.getGridSettings(drawGrid);
|
|
31
38
|
this.renderGrid();
|
|
@@ -51,7 +58,7 @@ export const GridLayer = PaperLayer.extend({
|
|
|
51
58
|
|
|
52
59
|
renderGrid() {
|
|
53
60
|
|
|
54
|
-
const {
|
|
61
|
+
const { paper } = this;
|
|
55
62
|
const { _gridSettings: gridSettings } = this;
|
|
56
63
|
|
|
57
64
|
this.removeGrid();
|
|
@@ -96,7 +103,7 @@ export const GridLayer = PaperLayer.extend({
|
|
|
96
103
|
|
|
97
104
|
updateGrid() {
|
|
98
105
|
|
|
99
|
-
const { _gridCache: grid, _gridSettings: gridSettings,
|
|
106
|
+
const { _gridCache: grid, _gridSettings: gridSettings, paper } = this;
|
|
100
107
|
if (!grid) return;
|
|
101
108
|
const { root: vSvg, patterns } = grid;
|
|
102
109
|
const { x, y, width, height } = paper.getArea();
|
|
@@ -114,7 +121,7 @@ export const GridLayer = PaperLayer.extend({
|
|
|
114
121
|
},
|
|
115
122
|
|
|
116
123
|
_getPatternId(index) {
|
|
117
|
-
return `pattern_${this.
|
|
124
|
+
return `pattern_${this.paper.cid}_${index}`;
|
|
118
125
|
},
|
|
119
126
|
|
|
120
127
|
_getGridRefs() {
|
|
@@ -143,30 +150,30 @@ export const GridLayer = PaperLayer.extend({
|
|
|
143
150
|
|
|
144
151
|
_resolveDrawGridOption(opt) {
|
|
145
152
|
|
|
146
|
-
|
|
153
|
+
const namespace = this.options.patterns;
|
|
147
154
|
if (isString(opt) && Array.isArray(namespace[opt])) {
|
|
148
155
|
return namespace[opt].map(function(item) {
|
|
149
156
|
return assign({}, item);
|
|
150
157
|
});
|
|
151
158
|
}
|
|
152
159
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
160
|
+
const options = opt || { args: [{}] };
|
|
161
|
+
const isArray = Array.isArray(options);
|
|
162
|
+
let name = options.name;
|
|
156
163
|
|
|
157
164
|
if (!isArray && !name && !options.markup) {
|
|
158
165
|
name = 'dot';
|
|
159
166
|
}
|
|
160
167
|
|
|
161
168
|
if (name && Array.isArray(namespace[name])) {
|
|
162
|
-
|
|
169
|
+
const pattern = namespace[name].map(function(item) {
|
|
163
170
|
return assign({}, item);
|
|
164
171
|
});
|
|
165
172
|
|
|
166
|
-
|
|
173
|
+
const args = Array.isArray(options.args) ? options.args : [options.args || {}];
|
|
167
174
|
|
|
168
175
|
defaults(args[0], omit(opt, 'args'));
|
|
169
|
-
for (
|
|
176
|
+
for (let i = 0; i < args.length; i++) {
|
|
170
177
|
if (pattern[i]) {
|
|
171
178
|
assign(pattern[i], args[i]);
|
|
172
179
|
}
|
|
@@ -1,34 +1,62 @@
|
|
|
1
1
|
import { View } from '../mvc/index.mjs';
|
|
2
|
-
import { addClassNamePrefix } from '../util/util.mjs';
|
|
2
|
+
import { addClassNamePrefix, clone } from '../util/util.mjs';
|
|
3
|
+
import { LAYER_VIEW_MARKER } from './symbols.mjs';
|
|
3
4
|
|
|
4
|
-
export const
|
|
5
|
-
GRID: 'grid',
|
|
6
|
-
CELLS: 'cells',
|
|
7
|
-
BACK: 'back',
|
|
8
|
-
FRONT: 'front',
|
|
9
|
-
TOOLS: 'tools',
|
|
10
|
-
LABELS: 'labels'
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export const PaperLayer = View.extend({
|
|
5
|
+
export const LayerView = View.extend({
|
|
14
6
|
|
|
15
7
|
tagName: 'g',
|
|
16
8
|
svgElement: true,
|
|
17
9
|
pivotNodes: null,
|
|
18
10
|
defaultTheme: null,
|
|
19
11
|
|
|
12
|
+
UPDATE_PRIORITY: 4,
|
|
13
|
+
|
|
20
14
|
options: {
|
|
21
|
-
|
|
15
|
+
id: ''
|
|
22
16
|
},
|
|
23
17
|
|
|
24
|
-
|
|
25
|
-
const { name } = this.options;
|
|
26
|
-
if (!name) return null;
|
|
27
|
-
return addClassNamePrefix(`${name}-layer`);
|
|
28
|
-
},
|
|
18
|
+
paper: null,
|
|
29
19
|
|
|
30
20
|
init: function() {
|
|
31
21
|
this.pivotNodes = {};
|
|
22
|
+
this.id = this.options.id || this.cid;
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
setPaperReference: function(paper) {
|
|
26
|
+
this.paper = paper;
|
|
27
|
+
this.afterPaperReferenceSet(paper);
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
unsetPaperReference: function() {
|
|
31
|
+
this.beforePaperReferenceUnset();
|
|
32
|
+
this.paper = null;
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
assertPaperReference() {
|
|
36
|
+
if (!this.paper) {
|
|
37
|
+
throw new Error('LayerView: paper reference is not set.');
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
afterPaperReferenceSet: function() {
|
|
42
|
+
// Can be overridden in subclasses.
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
beforePaperReferenceUnset: function() {
|
|
46
|
+
// Can be overridden in subclasses.
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
// prevents id to be set on the DOM element
|
|
50
|
+
_setAttributes: function(attrs) {
|
|
51
|
+
const newAttrs = clone(attrs);
|
|
52
|
+
delete newAttrs.id;
|
|
53
|
+
|
|
54
|
+
View.prototype._setAttributes.call(this, newAttrs);
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
className: function() {
|
|
58
|
+
const { id } = this.options;
|
|
59
|
+
return addClassNamePrefix(`${id}-layer`);
|
|
32
60
|
},
|
|
33
61
|
|
|
34
62
|
insertSortedNode: function(node, z) {
|
|
@@ -79,4 +107,11 @@ export const PaperLayer = View.extend({
|
|
|
79
107
|
return this.el.children.length === 0;
|
|
80
108
|
},
|
|
81
109
|
|
|
110
|
+
reset: function() {
|
|
111
|
+
this.removePivots();
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
Object.defineProperty(LayerView.prototype, LAYER_VIEW_MARKER, {
|
|
116
|
+
value: true,
|
|
82
117
|
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { GraphLayerView } from './GraphLayerView.mjs';
|
|
2
|
+
import { addClassNamePrefix } from '../util/util.mjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @class LegacyGraphLayerView
|
|
6
|
+
* @description A legacy GraphLayerView with an additional class name for backward compatibility.
|
|
7
|
+
*/
|
|
8
|
+
export const LegacyGraphLayerView = GraphLayerView.extend({
|
|
9
|
+
|
|
10
|
+
className: function() {
|
|
11
|
+
const className = GraphLayerView.prototype.className.apply(this, arguments);
|
|
12
|
+
return className + ' ' + addClassNamePrefix('viewport');
|
|
13
|
+
}
|
|
14
|
+
});
|