@joint/core 4.0.0

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.
Files changed (139) hide show
  1. package/LICENSE +376 -0
  2. package/README.md +49 -0
  3. package/dist/geometry.js +6486 -0
  4. package/dist/geometry.min.js +8 -0
  5. package/dist/joint.d.ts +5536 -0
  6. package/dist/joint.js +39629 -0
  7. package/dist/joint.min.js +8 -0
  8. package/dist/joint.nowrap.js +39626 -0
  9. package/dist/joint.nowrap.min.js +8 -0
  10. package/dist/vectorizer.js +9135 -0
  11. package/dist/vectorizer.min.js +8 -0
  12. package/dist/version.mjs +3 -0
  13. package/index.js +3 -0
  14. package/joint.mjs +27 -0
  15. package/package.json +192 -0
  16. package/src/V/annotation.mjs +0 -0
  17. package/src/V/index.mjs +2642 -0
  18. package/src/anchors/index.mjs +123 -0
  19. package/src/config/index.mjs +12 -0
  20. package/src/connectionPoints/index.mjs +202 -0
  21. package/src/connectionStrategies/index.mjs +73 -0
  22. package/src/connectors/curve.mjs +553 -0
  23. package/src/connectors/index.mjs +6 -0
  24. package/src/connectors/jumpover.mjs +452 -0
  25. package/src/connectors/normal.mjs +12 -0
  26. package/src/connectors/rounded.mjs +17 -0
  27. package/src/connectors/smooth.mjs +44 -0
  28. package/src/connectors/straight.mjs +110 -0
  29. package/src/dia/Cell.mjs +945 -0
  30. package/src/dia/CellView.mjs +1316 -0
  31. package/src/dia/Element.mjs +519 -0
  32. package/src/dia/ElementView.mjs +859 -0
  33. package/src/dia/Graph.mjs +1112 -0
  34. package/src/dia/HighlighterView.mjs +319 -0
  35. package/src/dia/Link.mjs +565 -0
  36. package/src/dia/LinkView.mjs +2207 -0
  37. package/src/dia/Paper.mjs +3171 -0
  38. package/src/dia/PaperLayer.mjs +75 -0
  39. package/src/dia/ToolView.mjs +69 -0
  40. package/src/dia/ToolsView.mjs +128 -0
  41. package/src/dia/attributes/calc.mjs +128 -0
  42. package/src/dia/attributes/connection.mjs +75 -0
  43. package/src/dia/attributes/defs.mjs +76 -0
  44. package/src/dia/attributes/eval.mjs +64 -0
  45. package/src/dia/attributes/index.mjs +69 -0
  46. package/src/dia/attributes/legacy.mjs +148 -0
  47. package/src/dia/attributes/offset.mjs +53 -0
  48. package/src/dia/attributes/props.mjs +30 -0
  49. package/src/dia/attributes/shape.mjs +92 -0
  50. package/src/dia/attributes/text.mjs +180 -0
  51. package/src/dia/index.mjs +13 -0
  52. package/src/dia/layers/GridLayer.mjs +176 -0
  53. package/src/dia/ports.mjs +874 -0
  54. package/src/elementTools/Control.mjs +153 -0
  55. package/src/elementTools/HoverConnect.mjs +37 -0
  56. package/src/elementTools/index.mjs +5 -0
  57. package/src/env/index.mjs +43 -0
  58. package/src/g/bezier.mjs +175 -0
  59. package/src/g/curve.mjs +956 -0
  60. package/src/g/ellipse.mjs +245 -0
  61. package/src/g/extend.mjs +64 -0
  62. package/src/g/geometry.helpers.mjs +58 -0
  63. package/src/g/index.mjs +17 -0
  64. package/src/g/intersection.mjs +511 -0
  65. package/src/g/line.bearing.mjs +30 -0
  66. package/src/g/line.length.mjs +5 -0
  67. package/src/g/line.mjs +356 -0
  68. package/src/g/line.squaredLength.mjs +10 -0
  69. package/src/g/path.mjs +2260 -0
  70. package/src/g/point.mjs +375 -0
  71. package/src/g/points.mjs +247 -0
  72. package/src/g/polygon.mjs +51 -0
  73. package/src/g/polyline.mjs +523 -0
  74. package/src/g/rect.mjs +556 -0
  75. package/src/g/types.mjs +10 -0
  76. package/src/highlighters/addClass.mjs +27 -0
  77. package/src/highlighters/index.mjs +5 -0
  78. package/src/highlighters/list.mjs +111 -0
  79. package/src/highlighters/mask.mjs +220 -0
  80. package/src/highlighters/opacity.mjs +17 -0
  81. package/src/highlighters/stroke.mjs +100 -0
  82. package/src/layout/index.mjs +4 -0
  83. package/src/layout/ports/port.mjs +188 -0
  84. package/src/layout/ports/portLabel.mjs +224 -0
  85. package/src/linkAnchors/index.mjs +76 -0
  86. package/src/linkTools/Anchor.mjs +235 -0
  87. package/src/linkTools/Arrowhead.mjs +103 -0
  88. package/src/linkTools/Boundary.mjs +48 -0
  89. package/src/linkTools/Button.mjs +121 -0
  90. package/src/linkTools/Connect.mjs +85 -0
  91. package/src/linkTools/HoverConnect.mjs +161 -0
  92. package/src/linkTools/Segments.mjs +393 -0
  93. package/src/linkTools/Vertices.mjs +253 -0
  94. package/src/linkTools/helpers.mjs +33 -0
  95. package/src/linkTools/index.mjs +8 -0
  96. package/src/mvc/Collection.mjs +560 -0
  97. package/src/mvc/Data.mjs +46 -0
  98. package/src/mvc/Dom/Dom.mjs +587 -0
  99. package/src/mvc/Dom/Event.mjs +130 -0
  100. package/src/mvc/Dom/animations.mjs +122 -0
  101. package/src/mvc/Dom/events.mjs +69 -0
  102. package/src/mvc/Dom/index.mjs +13 -0
  103. package/src/mvc/Dom/methods.mjs +392 -0
  104. package/src/mvc/Dom/props.mjs +77 -0
  105. package/src/mvc/Dom/vars.mjs +5 -0
  106. package/src/mvc/Events.mjs +337 -0
  107. package/src/mvc/Listener.mjs +33 -0
  108. package/src/mvc/Model.mjs +239 -0
  109. package/src/mvc/View.mjs +323 -0
  110. package/src/mvc/ViewBase.mjs +182 -0
  111. package/src/mvc/index.mjs +9 -0
  112. package/src/mvc/mvcUtils.mjs +90 -0
  113. package/src/polyfills/array.js +4 -0
  114. package/src/polyfills/base64.js +68 -0
  115. package/src/polyfills/index.mjs +5 -0
  116. package/src/polyfills/number.js +3 -0
  117. package/src/polyfills/string.js +3 -0
  118. package/src/polyfills/typedArray.js +47 -0
  119. package/src/routers/index.mjs +6 -0
  120. package/src/routers/manhattan.mjs +856 -0
  121. package/src/routers/metro.mjs +91 -0
  122. package/src/routers/normal.mjs +6 -0
  123. package/src/routers/oneSide.mjs +60 -0
  124. package/src/routers/orthogonal.mjs +323 -0
  125. package/src/routers/rightAngle.mjs +1056 -0
  126. package/src/shapes/index.mjs +3 -0
  127. package/src/shapes/standard.mjs +755 -0
  128. package/src/util/cloneCells.mjs +67 -0
  129. package/src/util/getRectPoint.mjs +65 -0
  130. package/src/util/index.mjs +5 -0
  131. package/src/util/svgTagTemplate.mjs +110 -0
  132. package/src/util/util.mjs +1754 -0
  133. package/src/util/utilHelpers.mjs +2402 -0
  134. package/src/util/wrappers.mjs +56 -0
  135. package/types/geometry.d.ts +815 -0
  136. package/types/index.d.ts +53 -0
  137. package/types/joint.d.ts +4391 -0
  138. package/types/joint.head.d.ts +12 -0
  139. package/types/vectorizer.d.ts +327 -0
@@ -0,0 +1,75 @@
1
+ import { View } from '../mvc/index.mjs';
2
+ import { addClassNamePrefix } from '../util/util.mjs';
3
+
4
+ export const LayersNames = {
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({
14
+
15
+ tagName: 'g',
16
+ svgElement: true,
17
+ pivotNodes: null,
18
+ defaultTheme: null,
19
+
20
+ options: {
21
+ name: ''
22
+ },
23
+
24
+ className: function() {
25
+ return addClassNamePrefix(`${this.options.name}-layer`);
26
+ },
27
+
28
+ init: function() {
29
+ this.pivotNodes = {};
30
+ },
31
+
32
+ insertSortedNode: function(node, z) {
33
+ this.el.insertBefore(node, this.insertPivot(z));
34
+ },
35
+
36
+ insertNode: function(node) {
37
+ const { el } = this;
38
+ if (node.parentNode !== el) {
39
+ el.appendChild(node);
40
+ }
41
+ },
42
+
43
+ insertPivot: function(z) {
44
+ const { el, pivotNodes } = this;
45
+ z = +z;
46
+ z || (z = 0);
47
+ let pivotNode = pivotNodes[z];
48
+ if (pivotNode) return pivotNode;
49
+ pivotNode = pivotNodes[z] = document.createComment('z-index:' + (z + 1));
50
+ let neighborZ = -Infinity;
51
+ for (let currentZ in pivotNodes) {
52
+ currentZ = +currentZ;
53
+ if (currentZ < z && currentZ > neighborZ) {
54
+ neighborZ = currentZ;
55
+ if (neighborZ === z - 1) continue;
56
+ }
57
+ }
58
+ if (neighborZ !== -Infinity) {
59
+ const neighborPivot = pivotNodes[neighborZ];
60
+ // Insert After
61
+ el.insertBefore(pivotNode, neighborPivot.nextSibling);
62
+ } else {
63
+ // First Child
64
+ el.insertBefore(pivotNode, el.firstChild);
65
+ }
66
+ return pivotNode;
67
+ },
68
+
69
+ removePivots: function() {
70
+ const { el, pivotNodes } = this;
71
+ for (let z in pivotNodes) el.removeChild(pivotNodes[z]);
72
+ this.pivotNodes = {};
73
+ }
74
+
75
+ });
@@ -0,0 +1,69 @@
1
+ import * as mvc from '../mvc/index.mjs';
2
+
3
+ export const ToolView = mvc.View.extend({
4
+ name: null,
5
+ tagName: 'g',
6
+ className: 'tool',
7
+ svgElement: true,
8
+ _visible: true,
9
+
10
+ init: function() {
11
+ var name = this.name;
12
+ if (name) this.vel.attr('data-tool-name', name);
13
+ },
14
+
15
+ configure: function(view, toolsView) {
16
+ this.relatedView = view;
17
+ this.paper = view.paper;
18
+ this.parentView = toolsView;
19
+ this.simulateRelatedView(this.el);
20
+ // Delegate events in case the ToolView was removed from the DOM and reused.
21
+ this.delegateEvents();
22
+ return this;
23
+ },
24
+
25
+ simulateRelatedView: function(el) {
26
+ if (el) el.setAttribute('model-id', this.relatedView.model.id);
27
+ },
28
+
29
+ getName: function() {
30
+ return this.name;
31
+ },
32
+
33
+ show: function() {
34
+ this.el.style.display = '';
35
+ this._visible = true;
36
+ },
37
+
38
+ hide: function() {
39
+ this.el.style.display = 'none';
40
+ this._visible = false;
41
+ },
42
+
43
+ isVisible: function() {
44
+ return !!this._visible;
45
+ },
46
+
47
+ focus: function() {
48
+ var opacity = this.options.focusOpacity;
49
+ if (isFinite(opacity)) this.el.style.opacity = opacity;
50
+ this.parentView.focusTool(this);
51
+ },
52
+
53
+ blur: function() {
54
+ this.el.style.opacity = '';
55
+ this.parentView.blurTool(this);
56
+ },
57
+
58
+ update: function() {
59
+ // to be overridden
60
+ },
61
+
62
+ guard: function(evt) {
63
+ // Let the context-menu event bubble up to the relatedView
64
+ const { paper, relatedView } = this;
65
+ if (!paper || !relatedView) return true;
66
+ return paper.guard(evt, relatedView);
67
+ }
68
+ });
69
+
@@ -0,0 +1,128 @@
1
+ import * as mvc from '../mvc/index.mjs';
2
+ import * as util from '../util/index.mjs';
3
+ import { CellView } from './CellView.mjs';
4
+ import { LayersNames } from './PaperLayer.mjs';
5
+ import { ToolView } from './ToolView.mjs';
6
+
7
+ export const ToolsView = mvc.View.extend({
8
+ tagName: 'g',
9
+ className: 'tools',
10
+ svgElement: true,
11
+ tools: null,
12
+ isRendered: false,
13
+ options: {
14
+ tools: null,
15
+ relatedView: null,
16
+ name: null,
17
+ // layer?: LayersNames.TOOLS
18
+ // z?: number
19
+ },
20
+
21
+ configure: function(options) {
22
+ options = util.assign(this.options, options);
23
+ var tools = options.tools;
24
+ if (!Array.isArray(tools)) return this;
25
+ var relatedView = options.relatedView;
26
+ if (!(relatedView instanceof CellView)) return this;
27
+ var views = this.tools = [];
28
+ for (var i = 0, n = tools.length; i < n; i++) {
29
+ var tool = tools[i];
30
+ if (!(tool instanceof ToolView)) continue;
31
+ tool.configure(relatedView, this);
32
+ this.vel.append(tool.el);
33
+ views.push(tool);
34
+ }
35
+ this.isRendered = false;
36
+ relatedView.requestUpdate(relatedView.getFlag('TOOLS'));
37
+ return this;
38
+ },
39
+
40
+ getName: function() {
41
+ return this.options.name;
42
+ },
43
+
44
+ update: function(opt) {
45
+
46
+ opt || (opt = {});
47
+ var tools = this.tools;
48
+ if (!tools) return this;
49
+ var isRendered = this.isRendered;
50
+ for (var i = 0, n = tools.length; i < n; i++) {
51
+ var tool = tools[i];
52
+ if (!isRendered) {
53
+ // First update executes render()
54
+ tool.render();
55
+ } else if (opt.tool !== tool.cid && tool.isVisible()) {
56
+ tool.update();
57
+ }
58
+ }
59
+ if (!this.isMounted()) {
60
+ this.mount();
61
+ }
62
+ if (!isRendered) {
63
+ // Make sure tools are visible (if they were hidden and the tool removed)
64
+ this.blurTool();
65
+ this.isRendered = true;
66
+ }
67
+ return this;
68
+ },
69
+
70
+ focusTool: function(focusedTool) {
71
+
72
+ var tools = this.tools;
73
+ if (!tools) return this;
74
+ for (var i = 0, n = tools.length; i < n; i++) {
75
+ var tool = tools[i];
76
+ if (focusedTool === tool) {
77
+ tool.show();
78
+ } else {
79
+ tool.hide();
80
+ }
81
+ }
82
+ return this;
83
+ },
84
+
85
+ blurTool: function(blurredTool) {
86
+ var tools = this.tools;
87
+ if (!tools) return this;
88
+ for (var i = 0, n = tools.length; i < n; i++) {
89
+ var tool = tools[i];
90
+ if (tool !== blurredTool && !tool.isVisible()) {
91
+ tool.show();
92
+ tool.update();
93
+ }
94
+ }
95
+ return this;
96
+ },
97
+
98
+ hide: function() {
99
+ return this.focusTool(null);
100
+ },
101
+
102
+ show: function() {
103
+ return this.blurTool(null);
104
+ },
105
+
106
+ onRemove: function() {
107
+ var tools = this.tools;
108
+ if (!tools) return this;
109
+ for (var i = 0, n = tools.length; i < n; i++) {
110
+ tools[i].remove();
111
+ }
112
+ this.tools = null;
113
+ },
114
+
115
+ mount: function() {
116
+ const { options, el } = this;
117
+ const { relatedView, layer = LayersNames.TOOLS, z } = options;
118
+ if (relatedView) {
119
+ if (layer) {
120
+ relatedView.paper.getLayerView(layer).insertSortedNode(el, z);
121
+ } else {
122
+ relatedView.el.appendChild(el);
123
+ }
124
+ }
125
+ return this;
126
+ }
127
+
128
+ });
@@ -0,0 +1,128 @@
1
+ const props = {
2
+ x: 'x',
3
+ y: 'y',
4
+ width: 'w',
5
+ height: 'h',
6
+ minimum: 's',
7
+ maximum: 'l',
8
+ diagonal: 'd'
9
+ };
10
+ const propsList = Object.keys(props).map(key => props[key]).join('');
11
+ const numberPattern = '[-+]?[0-9]*\\.?[0-9]+(?:[eE][-+]?[0-9]+)?';
12
+ const findSpacesRegex = /\s/g;
13
+ const parseExpressionRegExp = new RegExp(`^(${numberPattern}\\*)?([${propsList}])(/${numberPattern})?([-+]{1,2}${numberPattern})?$`, 'g');
14
+
15
+ function throwInvalid(expression) {
16
+ throw new Error(`Invalid calc() expression: ${expression}`);
17
+ }
18
+
19
+ export function evalCalcExpression(expression, bbox) {
20
+ const match = parseExpressionRegExp.exec(expression.replace(findSpacesRegex, ''));
21
+ if (!match) throwInvalid(expression);
22
+ parseExpressionRegExp.lastIndex = 0; // reset regex results for the next run
23
+ const [,multiply, property, divide, add] = match;
24
+ const { x, y, width, height } = bbox;
25
+ let value = 0;
26
+ switch (property) {
27
+ case props.width: {
28
+ value = width;
29
+ break;
30
+ }
31
+ case props.height: {
32
+ value = height;
33
+ break;
34
+ }
35
+ case props.x: {
36
+ value = x;
37
+ break;
38
+ }
39
+ case props.y: {
40
+ value = y;
41
+ break;
42
+ }
43
+ case props.minimum: {
44
+ value = Math.min(height, width);
45
+ break;
46
+ }
47
+ case props.maximum: {
48
+ value = Math.max(height, width);
49
+ break;
50
+ }
51
+ case props.diagonal: {
52
+ value = Math.sqrt((height * height) + (width * width));
53
+ break;
54
+ }
55
+ }
56
+ if (multiply) {
57
+ // e.g "2*"
58
+ value *= parseFloat(multiply);
59
+ }
60
+ if (divide) {
61
+ // e.g "/2"
62
+ value /= parseFloat(divide.slice(1));
63
+ }
64
+ if (add) {
65
+ value += evalAddExpression(add);
66
+ }
67
+ return value;
68
+ }
69
+
70
+ function evalAddExpression(addExpression) {
71
+ if (!addExpression) return 0;
72
+ const [sign] = addExpression;
73
+ switch (sign) {
74
+ case '+': {
75
+ return parseFloat(addExpression.substr(1));
76
+ }
77
+ case '-': {
78
+ return -parseFloat(addExpression.substr(1));
79
+ }
80
+ }
81
+ return parseFloat(addExpression);
82
+ }
83
+
84
+ export function isCalcAttribute(value) {
85
+ return typeof value === 'string' && value.includes('calc');
86
+ }
87
+
88
+ const calcStart = 'calc(';
89
+ const calcStartOffset = calcStart.length;
90
+
91
+ export function evalCalcAttribute(attributeValue, refBBox) {
92
+ let value = attributeValue;
93
+ let startSearchIndex = 0;
94
+ do {
95
+ let calcIndex = value.indexOf(calcStart, startSearchIndex);
96
+ if (calcIndex === -1) return value;
97
+ let calcEndIndex = calcIndex + calcStartOffset;
98
+ let brackets = 1;
99
+ findClosingBracket: do {
100
+ switch (value[calcEndIndex]) {
101
+ case '(': {
102
+ brackets++;
103
+ break;
104
+ }
105
+ case ')': {
106
+ brackets--;
107
+ if (brackets === 0) break findClosingBracket;
108
+ break;
109
+ }
110
+ case undefined: {
111
+ // Could not find the closing bracket.
112
+ throwInvalid(value);
113
+ }
114
+ }
115
+ calcEndIndex++;
116
+ } while (true);
117
+ // Get the calc() expression without nested calcs (recursion)
118
+ let expression = value.slice(calcIndex + calcStartOffset, calcEndIndex);
119
+ if (isCalcAttribute(expression)) {
120
+ expression = evalCalcAttribute(expression, refBBox);
121
+ }
122
+ // Eval the calc() expression without nested calcs.
123
+ const calcValue = String(evalCalcExpression(expression, refBBox));
124
+ // Replace the calc() expression and continue search
125
+ value = value.slice(0, calcIndex) + calcValue + value.slice(calcEndIndex + 1);
126
+ startSearchIndex = calcIndex + calcValue.length;
127
+ } while (true);
128
+ }
@@ -0,0 +1,75 @@
1
+ import { Point } from '../../g/index.mjs';
2
+
3
+ function atConnectionWrapper(method, opt) {
4
+ var zeroVector = new Point(1, 0);
5
+ return function(value) {
6
+ var p, angle;
7
+ var tangent = this[method](value);
8
+ if (tangent) {
9
+ angle = (opt.rotate) ? tangent.vector().vectorAngle(zeroVector) : 0;
10
+ p = tangent.start;
11
+ } else {
12
+ p = this.path.start;
13
+ angle = 0;
14
+ }
15
+ if (angle === 0) return { transform: 'translate(' + p.x + ',' + p.y + ')' };
16
+ return { transform: 'translate(' + p.x + ',' + p.y + ') rotate(' + angle + ')' };
17
+ };
18
+ }
19
+
20
+ function isLinkView() {
21
+ return this.model.isLink();
22
+ }
23
+
24
+ const connectionAttributesNS = {
25
+
26
+ 'connection': {
27
+ qualify: isLinkView,
28
+ set: function({ stubs = 0 }) {
29
+ let d;
30
+ if (isFinite(stubs) && stubs !== 0) {
31
+ let offset;
32
+ if (stubs < 0) {
33
+ offset = (this.getConnectionLength() + stubs) / 2;
34
+ } else {
35
+ offset = stubs;
36
+ }
37
+ const path = this.getConnection();
38
+ const segmentSubdivisions = this.getConnectionSubdivisions();
39
+ const sourceParts = path.divideAtLength(offset, { segmentSubdivisions });
40
+ const targetParts = path.divideAtLength(-offset, { segmentSubdivisions });
41
+ if (sourceParts && targetParts) {
42
+ d = `${sourceParts[0].serialize()} ${targetParts[1].serialize()}`;
43
+ }
44
+ }
45
+
46
+ return { d: d || this.getSerializedConnection() };
47
+ }
48
+ },
49
+
50
+ 'at-connection-length-keep-gradient': {
51
+ qualify: isLinkView,
52
+ set: atConnectionWrapper('getTangentAtLength', { rotate: true })
53
+ },
54
+
55
+ 'at-connection-length-ignore-gradient': {
56
+ qualify: isLinkView,
57
+ set: atConnectionWrapper('getTangentAtLength', { rotate: false })
58
+ },
59
+
60
+ 'at-connection-ratio-keep-gradient': {
61
+ qualify: isLinkView,
62
+ set: atConnectionWrapper('getTangentAtRatio', { rotate: true })
63
+ },
64
+
65
+ 'at-connection-ratio-ignore-gradient': {
66
+ qualify: isLinkView,
67
+ set: atConnectionWrapper('getTangentAtRatio', { rotate: false })
68
+ }
69
+
70
+ };
71
+
72
+ connectionAttributesNS['at-connection-length'] = connectionAttributesNS['at-connection-length-keep-gradient'];
73
+ connectionAttributesNS['at-connection-ratio'] = connectionAttributesNS['at-connection-ratio-keep-gradient'];
74
+
75
+ export default connectionAttributesNS;
@@ -0,0 +1,76 @@
1
+ import { assign, isPlainObject } from '../../util/util.mjs';
2
+
3
+ function contextMarker(context) {
4
+ var marker = {};
5
+ // Stroke
6
+ // The context 'fill' is disregarded here. The usual case is to use the marker with a connection
7
+ // (for which 'fill' attribute is set to 'none').
8
+ var stroke = context.stroke;
9
+ if (typeof stroke === 'string') {
10
+ marker['stroke'] = stroke;
11
+ marker['fill'] = stroke;
12
+ }
13
+ // Opacity
14
+ // Again the context 'fill-opacity' is ignored.
15
+ var strokeOpacity = context['stroke-opacity'];
16
+ if (strokeOpacity === undefined) strokeOpacity = context.opacity;
17
+ if (strokeOpacity !== undefined) {
18
+ marker['stroke-opacity'] = strokeOpacity;
19
+ marker['fill-opacity'] = strokeOpacity;
20
+ }
21
+ return marker;
22
+ }
23
+
24
+ function setPaintURL(def) {
25
+ const { paper } = this;
26
+ const url = (def.type === 'pattern')
27
+ ? paper.definePattern(def)
28
+ : paper.defineGradient(def);
29
+ return `url(#${url})`;
30
+ }
31
+
32
+ const defsAttributesNS = {
33
+
34
+ 'source-marker': {
35
+ qualify: isPlainObject,
36
+ set: function(marker, refBBox, node, attrs) {
37
+ marker = assign(contextMarker(attrs), marker);
38
+ return { 'marker-start': 'url(#' + this.paper.defineMarker(marker) + ')' };
39
+ }
40
+ },
41
+
42
+ 'target-marker': {
43
+ qualify: isPlainObject,
44
+ set: function(marker, refBBox, node, attrs) {
45
+ marker = assign(contextMarker(attrs), { 'transform': 'rotate(180)' }, marker);
46
+ return { 'marker-end': 'url(#' + this.paper.defineMarker(marker) + ')' };
47
+ }
48
+ },
49
+
50
+ 'vertex-marker': {
51
+ qualify: isPlainObject,
52
+ set: function(marker, refBBox, node, attrs) {
53
+ marker = assign(contextMarker(attrs), marker);
54
+ return { 'marker-mid': 'url(#' + this.paper.defineMarker(marker) + ')' };
55
+ }
56
+ },
57
+
58
+ 'fill': {
59
+ qualify: isPlainObject,
60
+ set: setPaintURL
61
+ },
62
+
63
+ 'stroke': {
64
+ qualify: isPlainObject,
65
+ set: setPaintURL
66
+ },
67
+
68
+ 'filter': {
69
+ qualify: isPlainObject,
70
+ set: function(filter) {
71
+ return 'url(#' + this.paper.defineFilter(filter) + ')';
72
+ }
73
+ },
74
+ };
75
+
76
+ export default defsAttributesNS;
@@ -0,0 +1,64 @@
1
+ import { isCalcAttribute, evalCalcAttribute } from './calc.mjs';
2
+
3
+ const calcAttributesList = [
4
+ 'transform',
5
+ 'x',
6
+ 'y',
7
+ 'cx',
8
+ 'cy',
9
+ 'dx',
10
+ 'dy',
11
+ 'x1',
12
+ 'y1',
13
+ 'x2',
14
+ 'y2',
15
+ 'points',
16
+ 'd',
17
+ 'r',
18
+ 'rx',
19
+ 'ry',
20
+ 'width',
21
+ 'height',
22
+ 'stroke-width',
23
+ 'font-size',
24
+ ];
25
+
26
+ const positiveValueList = [
27
+ 'r',
28
+ 'rx',
29
+ 'ry',
30
+ 'width',
31
+ 'height',
32
+ 'stroke-width',
33
+ 'font-size',
34
+ ];
35
+
36
+ const calcAttributes = calcAttributesList.reduce((acc, attrName) => {
37
+ acc[attrName] = true;
38
+ return acc;
39
+ }, {});
40
+
41
+ const positiveValueAttributes = positiveValueList.reduce((acc, attrName) => {
42
+ acc[attrName] = true;
43
+ return acc;
44
+ }, {});
45
+
46
+ export function evalAttributes(attrs, refBBox) {
47
+ const evalAttrs = {};
48
+ for (let attrName in attrs) {
49
+ if (!attrs.hasOwnProperty(attrName)) continue;
50
+ evalAttrs[attrName] = evalAttribute(attrName, attrs[attrName], refBBox);
51
+ }
52
+ return evalAttrs;
53
+ }
54
+
55
+ export function evalAttribute(attrName, attrValue, refBBox) {
56
+ if (attrName in calcAttributes && isCalcAttribute(attrValue)) {
57
+ let evalAttrValue = evalCalcAttribute(attrValue, refBBox);
58
+ if (attrName in positiveValueAttributes) {
59
+ evalAttrValue = Math.max(0, evalAttrValue);
60
+ }
61
+ return evalAttrValue;
62
+ }
63
+ return attrValue;
64
+ }
@@ -0,0 +1,69 @@
1
+ import { assign, isPlainObject } from '../../util/util.mjs';
2
+ import $ from '../../mvc/Dom/index.mjs';
3
+ import V from '../../V/index.mjs';
4
+
5
+ import props from './props.mjs';
6
+ import legacyAttributesNS from './legacy.mjs';
7
+ import textAttributesNS from './text.mjs';
8
+ import connectionAttributesNS from './connection.mjs';
9
+ import shapeAttributesNS from './shape.mjs';
10
+ import defsAttributesNS from './defs.mjs';
11
+ import offsetAttributesNS from './offset.mjs';
12
+
13
+ function setIfChangedWrapper(attribute) {
14
+ return function setIfChanged(value, _, node) {
15
+ const vel = V(node);
16
+ if (vel.attr(attribute) === value) return;
17
+ vel.attr(attribute, value);
18
+ };
19
+ }
20
+
21
+ const attributesNS = {
22
+
23
+ 'ref': {
24
+ // We do not set `ref` attribute directly on an element.
25
+ // The attribute itself does not qualify for relative positioning.
26
+ },
27
+
28
+ 'href': {
29
+ set: setIfChangedWrapper('href')
30
+ },
31
+
32
+ 'xlink:href': {
33
+ set: setIfChangedWrapper('xlink:href')
34
+ },
35
+
36
+ // `port` attribute contains the `id` of the port that the underlying magnet represents.
37
+ 'port': {
38
+ set: function(port) {
39
+ return (port === null || port.id === undefined) ? port : port.id;
40
+ }
41
+ },
42
+
43
+ // `style` attribute is special in the sense that it sets the CSS style of the sub-element.
44
+ 'style': {
45
+ qualify: isPlainObject,
46
+ set: function(styles, refBBox, node) {
47
+ $(node).css(styles);
48
+ }
49
+ },
50
+
51
+ 'html': {
52
+ set: function(html, refBBox, node) {
53
+ $(node).html(html + '');
54
+ }
55
+ },
56
+
57
+ // Properties setter (set various properties on the node)
58
+ props,
59
+ };
60
+
61
+ assign(attributesNS, legacyAttributesNS);
62
+ assign(attributesNS, textAttributesNS);
63
+ assign(attributesNS, connectionAttributesNS);
64
+ assign(attributesNS, shapeAttributesNS);
65
+ assign(attributesNS, defsAttributesNS);
66
+ assign(attributesNS, offsetAttributesNS);
67
+
68
+ export const attributes = attributesNS;
69
+