@metadev/daga 4.0.1 → 4.0.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/Changelog.md CHANGED
@@ -6,6 +6,17 @@ List of releases and changes.
6
6
 
7
7
  ## Next release Joyeuse
8
8
 
9
+ ## v. 4.0.2
10
+
11
+ - Add grid style [#261](https://github.com/metadevpro/daga/pull/261)
12
+ - Fix bug where user could perform an action they are not allowed to by using the keyboard [#264](https://github.com/metadevpro/daga/pull/264)
13
+ - Fix bug with boolean input not displaying properly in React [#266](https://github.com/metadevpro/daga/pull/266)
14
+ - Fix bug with not being able to edit nested value sets in property editor in React [#267](https://github.com/metadevpro/daga/pull/267)
15
+ - Fix bug with hexadecimal characters not allowed in colors [#268](https://github.com/metadevpro/daga/pull/268)
16
+ - Make diagram decorators behave as extensions of their diagram node when clicking or hovering over them [#270](https://github.com/metadevpro/daga/pull/270)
17
+ - Make zoom not affect multiple selection rectangle [#271](https://github.com/metadevpro/daga/pull/271)
18
+ - Enable making decorators inherent to a node type [#272](https://github.com/metadevpro/daga/pull/272)
19
+
9
20
  ## v. 4.0.1
10
21
 
11
22
  - Ensure borders of nodes are fully contained within palette [#253](https://github.com/metadevpro/daga/pull/253)
package/index.cjs.js CHANGED
@@ -1167,24 +1167,6 @@ class DiagramElementSet extends DiagramEntitySet {
1167
1167
  }
1168
1168
  }
1169
1169
 
1170
- /**
1171
- * Returns whether the incoming timestamp wins over the existing timestamp.
1172
- *
1173
- * In the DiagramModel, timestamps that have never been set are left null;
1174
- * `timestampWins` treats that as an "initial timestamp" that loses to all LogicalTimestamps.
1175
- */
1176
- function timestampWins(incoming, existing) {
1177
- if (!existing) return true;
1178
- if (incoming[0] > existing[0]) return true;
1179
- if (incoming[0] === existing[0]) {
1180
- // In case of equality, declare the incoming timestamp the "winner".
1181
- // This occurs if a client reuses a timestamp for multiple actions in a row,
1182
- // in which case the last created should win.
1183
- return incoming[1] >= existing[1];
1184
- }
1185
- return false;
1186
- }
1187
-
1188
1170
  /**
1189
1171
  * A property which is part of a property set and defines what values a value in a value set can take.
1190
1172
  * @public
@@ -1301,6 +1283,121 @@ class PropertySet {
1301
1283
  return this.propertyList.length > 0;
1302
1284
  }
1303
1285
  }
1286
+
1287
+ /**
1288
+ * Returns whether the incoming timestamp wins over the existing timestamp.
1289
+ *
1290
+ * In the DiagramModel, timestamps that have never been set are left null;
1291
+ * `timestampWins` treats that as an "initial timestamp" that loses to all LogicalTimestamps.
1292
+ */
1293
+ function timestampWins(incoming, existing) {
1294
+ if (!existing) return true;
1295
+ if (incoming[0] > existing[0]) return true;
1296
+ if (incoming[0] === existing[0]) {
1297
+ // In case of equality, declare the incoming timestamp the "winner".
1298
+ // This occurs if a client reuses a timestamp for multiple actions in a row,
1299
+ // in which case the last created should win.
1300
+ return incoming[1] >= existing[1];
1301
+ }
1302
+ return false;
1303
+ }
1304
+
1305
+ /**
1306
+ * Checks if the given value is not empty.
1307
+ * @private
1308
+ * @param a A value.
1309
+ * @returns `true` if the given value is not `undefined`, `null`, `''`, `[]` or `{}`; `false` otherwise.
1310
+ */
1311
+ const empty = a => {
1312
+ return a === undefined || a === null || a === '' || a instanceof Array && a.length === 0 || a instanceof Object && Object.keys(a).length === 0;
1313
+ };
1314
+ /**
1315
+ * Checks whether the given values are equal.
1316
+ * @public
1317
+ * @param a A value.
1318
+ * @param b A value.
1319
+ * @returns `true` if the given values are equal, `false` otherwise.
1320
+ */
1321
+ const equals = (a, b) => {
1322
+ return a === b || JSON.stringify(a) === JSON.stringify(b);
1323
+ };
1324
+ /**
1325
+ * Calculates the differences between the two given objects and returns two objects containing the differences in each relative to the other.
1326
+ *
1327
+ * For each key that holds a different value in the two objects, the resulting objects will contain the differences in the values under that key.
1328
+ *
1329
+ * This function is recursive, that is, if the value under the key is an object, the function will be applied to that value recursively.
1330
+ *
1331
+ * @public
1332
+ * @param a An object.
1333
+ * @param b An object.
1334
+ * @returns A tuple of two objects with each containing the keys that have a different value in the corresponding argument compared to the other argument.
1335
+ */
1336
+ const diff = (a, b) => {
1337
+ const aDiff = {};
1338
+ const bDiff = {};
1339
+ const allKeys = [];
1340
+ for (const key in a) {
1341
+ allKeys.push(key);
1342
+ }
1343
+ for (const key in b) {
1344
+ if (!(key in a)) {
1345
+ allKeys.push(key);
1346
+ }
1347
+ }
1348
+ for (const key of allKeys) {
1349
+ if (isObject(a[key]) && isObject(b[key])) {
1350
+ const diffAB = diff(a[key], b[key]);
1351
+ // only add the key if differences are detected
1352
+ if (Object.keys(diffAB[0]).length > 0 && Object.keys(diffAB[1]).length > 0) {
1353
+ aDiff[key] = diffAB[0];
1354
+ bDiff[key] = diffAB[1];
1355
+ }
1356
+ } else {
1357
+ if (!equals(a[key], b[key])) {
1358
+ aDiff[key] = a[key];
1359
+ bDiff[key] = b[key];
1360
+ }
1361
+ }
1362
+ }
1363
+ return [aDiff, bDiff];
1364
+ };
1365
+ /**
1366
+ * Calculates the differences between the two given values of a valueset and returns two objects containing the differences in each relative to the other.
1367
+ *
1368
+ * @param a An object.
1369
+ * @param b An object.
1370
+ * @param valueSet A ValueSet to use as reference for the keys and types of each property.
1371
+ * @returns A tuple of two objects with each containing the keys that have a different value in the corresponding argument compared to the other argument.
1372
+ */
1373
+ const diffProperties = (a, b, valueSet) => {
1374
+ const aDiff = {};
1375
+ const bDiff = {};
1376
+ for (const key in valueSet.propertySet.propertyMap) {
1377
+ if (valueSet.propertySet.propertyMap[key].type === exports.Type.Object) {
1378
+ const diffAB = diffProperties(a[key], b[key], valueSet.getSubValueSet(key));
1379
+ // only add the key if differences are detected
1380
+ if (Object.keys(diffAB[0]).length > 0 && Object.keys(diffAB[1]).length > 0) {
1381
+ aDiff[key] = diffAB[0];
1382
+ bDiff[key] = diffAB[1];
1383
+ }
1384
+ } else {
1385
+ if (!equals(a[key], b[key])) {
1386
+ aDiff[key] = a[key];
1387
+ bDiff[key] = b[key];
1388
+ }
1389
+ }
1390
+ }
1391
+ return [aDiff, bDiff];
1392
+ };
1393
+ /**
1394
+ * Checks if the given value is an object.
1395
+ * @public
1396
+ * @param x A value.
1397
+ * @returns `true` if the given value is an object, `false` otherwise.
1398
+ */
1399
+ const isObject = x => x !== undefined && x !== null && x.constructor === Object;
1400
+
1304
1401
  /**
1305
1402
  * A set of values corresponding to a set of properties.
1306
1403
  * @public
@@ -1652,101 +1749,6 @@ class ValueSet {
1652
1749
  }
1653
1750
  }
1654
1751
  }
1655
- /**
1656
- * Checks if the given value is not empty.
1657
- * @private
1658
- * @param a A value.
1659
- * @returns `true` if the given value is not `undefined`, `null`, `''`, `[]` or `{}`; `false` otherwise.
1660
- */
1661
- const empty = a => {
1662
- return a === undefined || a === null || a === '' || a instanceof Array && a.length === 0 || a instanceof Object && Object.keys(a).length === 0;
1663
- };
1664
- /**
1665
- * Checks whether the given values are equal.
1666
- * @public
1667
- * @param a A value.
1668
- * @param b A value.
1669
- * @returns `true` if the given values are equal, `false` otherwise.
1670
- */
1671
- const equals = (a, b) => {
1672
- return a === b || JSON.stringify(a) === JSON.stringify(b);
1673
- };
1674
- /**
1675
- * Calculates the differences between the two given objects and returns two objects containing the differences in each relative to the other.
1676
- *
1677
- * For each key that holds a different value in the two objects, the resulting objects will contain the differences in the values under that key.
1678
- *
1679
- * This function is recursive, that is, if the value under the key is an object, the function will be applied to that value recursively.
1680
- *
1681
- * @public
1682
- * @param a An object.
1683
- * @param b An object.
1684
- * @returns A tuple of two objects with each containing the keys that have a different value in the corresponding argument compared to the other argument.
1685
- */
1686
- const diff = (a, b) => {
1687
- const aDiff = {};
1688
- const bDiff = {};
1689
- const allKeys = [];
1690
- for (const key in a) {
1691
- allKeys.push(key);
1692
- }
1693
- for (const key in b) {
1694
- if (!(key in a)) {
1695
- allKeys.push(key);
1696
- }
1697
- }
1698
- for (const key of allKeys) {
1699
- if (isObject(a[key]) && isObject(b[key])) {
1700
- const diffAB = diff(a[key], b[key]);
1701
- // only add the key if differences are detected
1702
- if (Object.keys(diffAB[0]).length > 0 && Object.keys(diffAB[1]).length > 0) {
1703
- aDiff[key] = diffAB[0];
1704
- bDiff[key] = diffAB[1];
1705
- }
1706
- } else {
1707
- if (!equals(a[key], b[key])) {
1708
- aDiff[key] = a[key];
1709
- bDiff[key] = b[key];
1710
- }
1711
- }
1712
- }
1713
- return [aDiff, bDiff];
1714
- };
1715
- /**
1716
- * Calculates the differences between the two given values of a valueset and returns two objects containing the differences in each relative to the other.
1717
- *
1718
- * @param a An object.
1719
- * @param b An object.
1720
- * @param valueSet A ValueSet to use as reference for the keys and types of each property.
1721
- * @returns A tuple of two objects with each containing the keys that have a different value in the corresponding argument compared to the other argument.
1722
- */
1723
- const diffProperties = (a, b, valueSet) => {
1724
- const aDiff = {};
1725
- const bDiff = {};
1726
- for (const key in valueSet.propertySet.propertyMap) {
1727
- if (valueSet.propertySet.propertyMap[key].type === exports.Type.Object) {
1728
- const diffAB = diffProperties(a[key], b[key], valueSet.getSubValueSet(key));
1729
- // only add the key if differences are detected
1730
- if (Object.keys(diffAB[0]).length > 0 && Object.keys(diffAB[1]).length > 0) {
1731
- aDiff[key] = diffAB[0];
1732
- bDiff[key] = diffAB[1];
1733
- }
1734
- } else {
1735
- if (!equals(a[key], b[key])) {
1736
- aDiff[key] = a[key];
1737
- bDiff[key] = b[key];
1738
- }
1739
- }
1740
- }
1741
- return [aDiff, bDiff];
1742
- };
1743
- /**
1744
- * Checks if the given value is an object.
1745
- * @public
1746
- * @param x A value.
1747
- * @returns `true` if the given value is an object, `false` otherwise.
1748
- */
1749
- const isObject = x => x !== undefined && x !== null && x.constructor === Object;
1750
1752
 
1751
1753
  /**
1752
1754
  * Default values of the parameters of a diagram connection.
@@ -2983,6 +2985,7 @@ const DIAGRAM_NODE_TYPE_DEFAULTS = {
2983
2985
  padding: 0,
2984
2986
  label: null,
2985
2987
  ports: [],
2988
+ decorators: [],
2986
2989
  sectionGrid: null,
2987
2990
  look: DIAGRAM_NODE_LOOK_DEFAULTS,
2988
2991
  isUnique: false,
@@ -3013,6 +3016,7 @@ class DiagramNodeType {
3013
3016
  this.topPadding = getTopPadding(values);
3014
3017
  this.label = values.label;
3015
3018
  this.ports = values.ports;
3019
+ this.decorators = values.decorators;
3016
3020
  this.sectionGrid = values.sectionGrid ? new DiagramSectionGrid(values.sectionGrid) : null;
3017
3021
  const looks = extractLooksFromConfig(values.look);
3018
3022
  this.defaultLook = looks.defaultLook;
@@ -3654,7 +3658,7 @@ class DiagramNodeSet extends DiagramElementSet {
3654
3658
  for (let i = 0; i < nodeType.ports.length; ++i) {
3655
3659
  const portConfig = nodeType.ports[i];
3656
3660
  const portType = portConfig.type !== undefined ? this.model.ports.types.get(portConfig.type) : undefined;
3657
- const port = this.model.ports.new(portType, node, [node.coords[0] + portConfig.coords[0], node.coords[1] + portConfig.coords[1]], portConfig.connectionPoint !== undefined ? [node.coords[0] + (portConfig.connectionPoint[0] || 0), node.coords[1] + (portConfig.connectionPoint[1] || 0)] : undefined, portConfig.direction, `${node.id}_${i}`);
3661
+ const port = this.model.ports.new(portType, node, [node.coords[0] + portConfig.coords[0], node.coords[1] + portConfig.coords[1]], portConfig.connectionPoint !== undefined ? [node.coords[0] + (portConfig.connectionPoint[0] || 0), node.coords[1] + (portConfig.connectionPoint[1] || 0)] : undefined, portConfig.direction, `${node.id}_port_${i}`);
3658
3662
  if ((_e = port.type) === null || _e === undefined ? undefined : _e.label) {
3659
3663
  const labelConfiguration = Object.assign(Object.assign({}, DIAGRAM_FIELD_DEFAULTS), (_f = port.type) === null || _f === undefined ? undefined : _f.label);
3660
3664
  const labelWidth = 6 * labelConfiguration.fontSize + getLeftPadding$1(labelConfiguration) + getRightPadding$1(labelConfiguration);
@@ -3681,6 +3685,13 @@ class DiagramNodeSet extends DiagramElementSet {
3681
3685
  const labelConfiguration = Object.assign(Object.assign({}, DIAGRAM_FIELD_DEFAULTS), nodeType.label);
3682
3686
  this.model.fields.new(node, [node.coords[0] + getLeftMargin(labelConfiguration), node.coords[1] + getTopMargin(labelConfiguration)], labelConfiguration.fontSize, labelConfiguration.fontFamily, labelConfiguration.color, labelConfiguration.selectedColor, node.width - getLeftMargin(labelConfiguration) - getRightMargin(labelConfiguration), node.height - getTopMargin(labelConfiguration) - getBottomMargin(labelConfiguration), labelConfiguration.horizontalAlign, labelConfiguration.verticalAlign, '', labelConfiguration.editable, labelConfiguration.fit);
3683
3687
  }
3688
+ // add node decorators
3689
+ if (nodeType.decorators.length > 0) {
3690
+ for (let i = 0; i < nodeType.decorators.length; ++i) {
3691
+ const decoratorConfig = nodeType.decorators[i];
3692
+ this.model.decorators.new(node, [node.coords[0] + decoratorConfig.coords[0], node.coords[1] + decoratorConfig.coords[1]], decoratorConfig.width, decoratorConfig.height, node.getPriority(), decoratorConfig.html, `${node.id}_decorator_${i}`);
3693
+ }
3694
+ }
3684
3695
  node.valueSet.resetValues();
3685
3696
  (_g = node.model.canvas) === null || _g === undefined ? undefined : _g.fitNodeInView(node.id);
3686
3697
  return node;
@@ -4209,6 +4220,13 @@ class DagaImporter {
4209
4220
  newNode.width = node.width;
4210
4221
  newNode.height = node.height;
4211
4222
  if (node.label) {
4223
+ // add node decorators
4224
+ if (newNodeType.decorators) {
4225
+ for (let i = 0; i < newNodeType.decorators.length; ++i) {
4226
+ const decoratorConfig = newNodeType.decorators[i];
4227
+ model.decorators.new(newNode, [newNode.coords[0] + decoratorConfig.coords[0], newNode.coords[1] + decoratorConfig.coords[1]], decoratorConfig.width, decoratorConfig.height, newNode.getPriority(), decoratorConfig.html, `${newNode.id}_decorator_${i}`);
4228
+ }
4229
+ }
4212
4230
  // add node label
4213
4231
  if (newNodeType.label) {
4214
4232
  const labelConfiguration = Object.assign(Object.assign({}, DIAGRAM_FIELD_DEFAULTS), newNodeType.label);
@@ -5930,6 +5948,32 @@ const updateLook = selection => {
5930
5948
  selection.filter('.stretchable-image-look').select('image.bottom-image').attr('x', d => d.look.leftMargin).attr('y', d => d.height - d.look.bottomMargin).attr('width', d => d.width - d.look.rightMargin - d.look.leftMargin).attr('height', d => d.look.bottomMargin).attr('href', d => d.look.backgroundImageBottom);
5931
5949
  selection.filter('.stretchable-image-look').select('image.bottom-right-image').attr('x', d => d.width - d.look.rightMargin).attr('y', d => d.height - d.look.bottomMargin).attr('width', d => d.look.rightMargin).attr('height', d => d.look.bottomMargin).attr('href', d => d.look.backgroundImageBottomRight);
5932
5950
  };
5951
+ const GRID_DEFAULTS = {
5952
+ enabled: true,
5953
+ style: 'dots',
5954
+ color: 'rgba(0, 0, 0, 0.1)',
5955
+ snap: false,
5956
+ spacing: 10,
5957
+ thickness: 0.05
5958
+ };
5959
+ const initializeGrid = (canvas, canvasView, backgroundPatternId) => {
5960
+ const canvasDefs = canvasView.append('defs');
5961
+ if (canvas.gridSize > 0 && isFinite(canvas.gridSize)) {
5962
+ const canvasBackgroundPattern = canvasDefs.append('pattern').attr('id', backgroundPatternId).attr('x', -canvas.gridSize / 2).attr('y', -canvas.gridSize / 2).attr('width', canvas.gridSize).attr('height', canvas.gridSize).attr('patternUnits', 'userSpaceOnUse');
5963
+ canvasBackgroundPattern.append('rect').attr('x', 0).attr('y', 0).attr('width', canvas.gridSize).attr('height', canvas.gridSize).attr('fill', canvas.backgroundColor);
5964
+ switch (canvas.gridStyle) {
5965
+ case 'dots':
5966
+ canvasBackgroundPattern.append('circle').attr('cx', canvas.gridSize / 2).attr('cy', canvas.gridSize / 2).attr('r', canvas.gridSize * canvas.gridThickness).attr('fill', canvas.gridColor);
5967
+ break;
5968
+ case 'lines':
5969
+ canvasBackgroundPattern.append('line').attr('x1', canvas.gridSize / 2).attr('x2', canvas.gridSize / 2).attr('y1', 0).attr('y2', canvas.gridSize).attr('stroke-width', canvas.gridSize * canvas.gridThickness).attr('stroke', canvas.gridColor);
5970
+ canvasBackgroundPattern.append('line').attr('x1', 0).attr('x2', (canvas.gridSize - canvas.gridSize * canvas.gridThickness) / 2).attr('y1', canvas.gridSize / 2).attr('y2', canvas.gridSize / 2).attr('stroke-width', canvas.gridSize * canvas.gridThickness).attr('stroke', canvas.gridColor);
5971
+ canvasBackgroundPattern.append('line').attr('x1', (canvas.gridSize + canvas.gridSize * canvas.gridThickness) / 2).attr('x2', canvas.gridSize).attr('y1', canvas.gridSize / 2).attr('y2', canvas.gridSize / 2).attr('stroke-width', canvas.gridSize * canvas.gridThickness).attr('stroke', canvas.gridColor);
5972
+ break;
5973
+ }
5974
+ canvasView.select('rect').attr('fill', `url(#${backgroundPatternId})`);
5975
+ }
5976
+ };
5933
5977
 
5934
5978
  const CONTEXT_MENU_MENU_RADIUS = 96;
5935
5979
  const CONTEXT_MENU_BUTTON_RADIUS = 32;
@@ -6099,7 +6143,7 @@ class DiagramUserHighlight extends DiagramElementSet {
6099
6143
  focusOn(element) {
6100
6144
  this.clear();
6101
6145
  this.focus = element;
6102
- if (element instanceof DiagramField && element.rootElement) {
6146
+ if ((element instanceof DiagramField || element instanceof DiagramDecorator) && element.rootElement) {
6103
6147
  this.focusOn(element.rootElement);
6104
6148
  } else {
6105
6149
  this.add(element);
@@ -6587,7 +6631,7 @@ class DiagramCanvas {
6587
6631
  * @param config The configuration object used to set the parameters of this canvas.
6588
6632
  */
6589
6633
  constructor(parentComponent, config) {
6590
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
6634
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
6591
6635
  this.backgroundPatternId = `daga-background-pattern-id-${DiagramCanvas.canvasCount++}`;
6592
6636
  this.zoomTransform = d3__namespace.zoomIdentity;
6593
6637
  // used to distinguish drags from clicks when dragging elements and during multiple selection
@@ -6606,15 +6650,16 @@ class DiagramCanvas {
6606
6650
  this.userHighlight = new DiagramUserHighlight(this);
6607
6651
  this.contextMenu = new DiagramContextMenu(this, (_a = config.canvas) === null || _a === undefined ? undefined : _a.contextMenu);
6608
6652
  this.backgroundColor = ((_b = config.canvas) === null || _b === undefined ? undefined : _b.backgroundColor) || '#FFFFFF';
6609
- this.gridSize = ((_d = (_c = config.canvas) === null || _c === undefined ? undefined : _c.grid) === null || _d === undefined ? undefined : _d.enabled) === false || ((_e = config.canvas) === null || _e === undefined ? undefined : _e.grid) === undefined ? 0 : Math.abs(((_g = (_f = config.canvas) === null || _f === undefined ? undefined : _f.grid) === null || _g === undefined ? undefined : _g.spacing) || 10);
6610
- this.gridThickness = Math.abs(((_j = (_h = config.canvas) === null || _h === undefined ? undefined : _h.grid) === null || _j === undefined ? undefined : _j.thickness) || 0.05);
6611
- this.gridColor = ((_l = (_k = config.canvas) === null || _k === undefined ? undefined : _k.grid) === null || _l === undefined ? undefined : _l.color) || 'rgba(0, 0, 0, 0.1)';
6612
- this.snapToGrid = ((_o = (_m = config.canvas) === null || _m === undefined ? undefined : _m.grid) === null || _o === undefined ? undefined : _o.enabled) === false || ((_p = config.canvas) === null || _p === undefined ? undefined : _p.grid) === undefined ? false : ((_r = (_q = config.canvas) === null || _q === undefined ? undefined : _q.grid) === null || _r === undefined ? undefined : _r.snap) || false;
6613
- this.zoomFactor = ((_s = config.canvas) === null || _s === undefined ? undefined : _s.zoomFactor) || 2;
6614
- this.panRate = ((_t = config.canvas) === null || _t === undefined ? undefined : _t.panRate) || 100;
6653
+ this.gridStyle = (_e = (_d = (_c = config.canvas) === null || _c === undefined ? undefined : _c.grid) === null || _d === undefined ? undefined : _d.style) !== null && _e !== undefined ? _e : GRID_DEFAULTS.style;
6654
+ this.gridSize = ((_g = (_f = config.canvas) === null || _f === undefined ? undefined : _f.grid) === null || _g === undefined ? undefined : _g.enabled) === false || ((_h = config.canvas) === null || _h === undefined ? undefined : _h.grid) === undefined ? 0 : Math.abs(((_k = (_j = config.canvas) === null || _j === undefined ? undefined : _j.grid) === null || _k === undefined ? undefined : _k.spacing) || GRID_DEFAULTS.spacing);
6655
+ this.gridThickness = Math.abs(((_m = (_l = config.canvas) === null || _l === undefined ? undefined : _l.grid) === null || _m === undefined ? undefined : _m.thickness) || GRID_DEFAULTS.thickness);
6656
+ this.gridColor = ((_p = (_o = config.canvas) === null || _o === undefined ? undefined : _o.grid) === null || _p === undefined ? undefined : _p.color) || GRID_DEFAULTS.color;
6657
+ this.snapToGrid = ((_r = (_q = config.canvas) === null || _q === undefined ? undefined : _q.grid) === null || _r === undefined ? undefined : _r.enabled) === false || ((_s = config.canvas) === null || _s === undefined ? undefined : _s.grid) === undefined ? false : ((_u = (_t = config.canvas) === null || _t === undefined ? undefined : _t.grid) === null || _u === undefined ? undefined : _u.snap) || GRID_DEFAULTS.snap;
6658
+ this.zoomFactor = ((_v = config.canvas) === null || _v === undefined ? undefined : _v.zoomFactor) || 2;
6659
+ this.panRate = ((_w = config.canvas) === null || _w === undefined ? undefined : _w.panRate) || 100;
6615
6660
  this.inferConnectionType = config.inferConnectionType || false;
6616
6661
  this.multipleSelectionOn = false;
6617
- this.priorityThresholds = ((_u = config.canvas) === null || _u === undefined ? undefined : _u.priorityThresholds) || [];
6662
+ this.priorityThresholds = ((_x = config.canvas) === null || _x === undefined ? undefined : _x.priorityThresholds) || [];
6618
6663
  this.priorityThreshold = this.priorityThresholds ? this.priorityThresholds[0] : undefined;
6619
6664
  this.layoutFormat = config.layoutFormat;
6620
6665
  this.userActions = config.userActions || {};
@@ -6741,23 +6786,29 @@ class DiagramCanvas {
6741
6786
  }
6742
6787
  }
6743
6788
  if (event.ctrlKey && event.key === 'c') {
6744
- event.preventDefault();
6745
- // copy
6746
- this.userSelection.copyToClipboard();
6747
- this.cancelAllUserActions();
6789
+ if (this.canUserPerformAction(exports.DiagramActions.Clipboard)) {
6790
+ event.preventDefault();
6791
+ // copy
6792
+ this.userSelection.copyToClipboard();
6793
+ this.cancelAllUserActions();
6794
+ }
6748
6795
  }
6749
6796
  if (event.ctrlKey && event.key === 'x') {
6750
- event.preventDefault();
6751
- // cut
6752
- this.userSelection.cutToClipboard();
6753
- this.cancelAllUserActions();
6797
+ if (this.canUserPerformAction(exports.DiagramActions.Clipboard) && this.canUserPerformAction(exports.DiagramActions.Remove)) {
6798
+ event.preventDefault();
6799
+ // cut
6800
+ this.userSelection.cutToClipboard();
6801
+ this.cancelAllUserActions();
6802
+ }
6754
6803
  }
6755
6804
  if (event.ctrlKey && event.key === 'v') {
6756
- event.preventDefault();
6757
- // paste
6758
- const coordinateRange = this.getCoordinatesOnScreen();
6759
- this.userSelection.pasteFromClipboard(this.getClosestGridPoint([(coordinateRange[0][0] + coordinateRange[1][0]) / 2, (coordinateRange[0][1] + coordinateRange[1][1]) / 2]));
6760
- this.cancelAllUserActions();
6805
+ if (this.canUserPerformAction(exports.DiagramActions.Paste)) {
6806
+ event.preventDefault();
6807
+ // paste
6808
+ const coordinateRange = this.getCoordinatesOnScreen();
6809
+ this.userSelection.pasteFromClipboard(this.getClosestGridPoint([(coordinateRange[0][0] + coordinateRange[1][0]) / 2, (coordinateRange[0][1] + coordinateRange[1][1]) / 2]));
6810
+ this.cancelAllUserActions();
6811
+ }
6761
6812
  }
6762
6813
  if (event.ctrlKey && event.key === 'y') {
6763
6814
  event.preventDefault();
@@ -6770,38 +6821,50 @@ class DiagramCanvas {
6770
6821
  this.actionStack.undo();
6771
6822
  }
6772
6823
  if (event.key === '+') {
6773
- event.preventDefault();
6774
- // zoom in
6775
- this.zoomBy(this.zoomFactor);
6824
+ if (this.canUserPerformAction(exports.DiagramActions.Zoom)) {
6825
+ event.preventDefault();
6826
+ // zoom in
6827
+ this.zoomBy(this.zoomFactor);
6828
+ }
6776
6829
  }
6777
6830
  if (event.key === '-') {
6778
- event.preventDefault();
6779
- // zoom out
6780
- this.zoomBy(1 / this.zoomFactor);
6831
+ if (this.canUserPerformAction(exports.DiagramActions.Zoom)) {
6832
+ event.preventDefault();
6833
+ // zoom out
6834
+ this.zoomBy(1 / this.zoomFactor);
6835
+ }
6781
6836
  }
6782
6837
  if (event.key === exports.Keys.ArrowLeft) {
6783
- event.preventDefault();
6784
- // move left, faster if we're zoomed out and slower if we're zoomed in
6785
- this.translateBy(this.panRate / this.zoomTransform.k, 0);
6838
+ if (this.canUserPerformAction(exports.DiagramActions.Zoom)) {
6839
+ event.preventDefault();
6840
+ // move left, faster if we're zoomed out and slower if we're zoomed in
6841
+ this.translateBy(this.panRate / this.zoomTransform.k, 0);
6842
+ }
6786
6843
  }
6787
6844
  if (event.key === exports.Keys.ArrowRight) {
6788
- event.preventDefault();
6789
- // move right, faster if we're zoomed out and slower if we're zoomed in
6790
- this.translateBy(-this.panRate / this.zoomTransform.k, 0);
6845
+ if (this.canUserPerformAction(exports.DiagramActions.Zoom)) {
6846
+ event.preventDefault();
6847
+ // move right, faster if we're zoomed out and slower if we're zoomed in
6848
+ this.translateBy(-this.panRate / this.zoomTransform.k, 0);
6849
+ }
6791
6850
  }
6792
6851
  if (event.key === exports.Keys.ArrowDown) {
6793
- event.preventDefault();
6794
- // move down, faster if we're zoomed out and slower if we're zoomed in
6795
- this.translateBy(0, -this.panRate / this.zoomTransform.k);
6852
+ if (this.canUserPerformAction(exports.DiagramActions.Zoom)) {
6853
+ event.preventDefault();
6854
+ // move down, faster if we're zoomed out and slower if we're zoomed in
6855
+ this.translateBy(0, -this.panRate / this.zoomTransform.k);
6856
+ }
6796
6857
  }
6797
6858
  if (event.key === exports.Keys.ArrowUp) {
6798
- event.preventDefault();
6799
- // move up, faster if we're zoomed out and slower if we're zoomed in
6800
- this.translateBy(0, this.panRate / this.zoomTransform.k);
6859
+ if (this.canUserPerformAction(exports.DiagramActions.Zoom)) {
6860
+ event.preventDefault();
6861
+ // move up, faster if we're zoomed out and slower if we're zoomed in
6862
+ this.translateBy(0, this.panRate / this.zoomTransform.k);
6863
+ }
6801
6864
  }
6802
6865
  });
6803
6866
  const canvasView = this.selectSVGElement().append('g').attr('class', 'daga-canvas-view').attr('width', `100%`).attr('height', `100%`);
6804
- const canvasBackground = canvasView.append('rect').attr('x', 0).attr('y', 0).attr('width', `100%`).attr('height', `100%`).attr('fill', this.backgroundColor).attr('stroke-width', '0').on(exports.Events.MouseMove, event => {
6867
+ canvasView.append('rect').attr('x', 0).attr('y', 0).attr('width', `100%`).attr('height', `100%`).attr('fill', this.backgroundColor).attr('stroke-width', '0').on(exports.Events.MouseMove, event => {
6805
6868
  if (this.unfinishedConnection !== undefined) {
6806
6869
  const pointerCoords = this.getPointerLocationRelativeToCanvas(event);
6807
6870
  this.unfinishedConnection.endCoords = pointerCoords;
@@ -6857,13 +6920,7 @@ class DiagramCanvas {
6857
6920
  }).on(exports.ZoomEvents.End, () => {
6858
6921
  setCursorStyle();
6859
6922
  }));
6860
- const canvasDefs = canvasView.append('defs');
6861
- if (this.gridSize > 0 && isFinite(this.gridSize)) {
6862
- const canvasBackgroundPattern = canvasDefs.append('pattern').attr('id', this.backgroundPatternId).attr('x', -this.gridSize / 2).attr('y', -this.gridSize / 2).attr('width', this.gridSize).attr('height', this.gridSize).attr('patternUnits', 'userSpaceOnUse');
6863
- canvasBackgroundPattern.append('rect').attr('x', 0).attr('y', 0).attr('width', this.gridSize).attr('height', this.gridSize).attr('fill', this.backgroundColor);
6864
- canvasBackgroundPattern.append('circle').attr('cx', this.gridSize / 2).attr('cy', this.gridSize / 2).attr('r', this.gridSize * this.gridThickness).attr('fill', this.gridColor);
6865
- canvasBackground.attr('fill', `url(#${this.backgroundPatternId})`);
6866
- }
6923
+ initializeGrid(this, canvasView, this.backgroundPatternId);
6867
6924
  canvasView.append('g').attr('class', 'daga-canvas-elements');
6868
6925
  }
6869
6926
  zoomBy(factor) {
@@ -7839,7 +7896,23 @@ class DiagramCanvas {
7839
7896
  const mergeSelection = enterSelection.merge(updateSelection);
7840
7897
  mergeSelection.attr('width', d => `${d.width}px`).attr('height', d => `${d.height}px`).attr('transform', d => `translate(${d.coords[0]},${d.coords[1]})`).html(d => d.html);
7841
7898
  exitSelection.remove();
7842
- enterSelection.on(exports.Events.ContextMenu, (event, d) => {
7899
+ enterSelection.on(exports.Events.MouseOver, (_event, d) => {
7900
+ if (!this.dragging) {
7901
+ this.userHighlight.focusOn(d);
7902
+ this.diagramEvent$.next(new DiagramHighlightedEvent(d));
7903
+ }
7904
+ }).on(exports.Events.Click, (event, d) => {
7905
+ if (!event.ctrlKey && !event.shiftKey) {
7906
+ const deselectedElements = this.userSelection.all();
7907
+ this.userSelection.clear();
7908
+ this.diagramEvent$.next(new DiagramSelectionEvent(deselectedElements, false));
7909
+ }
7910
+ if (d.rootElement) {
7911
+ const elementToBeToggled = getRelatedNodeOrItself(d.rootElement);
7912
+ this.userSelection.toggle(elementToBeToggled);
7913
+ this.diagramEvent$.next(new DiagramSelectionEvent([elementToBeToggled], elementToBeToggled.selected));
7914
+ }
7915
+ }).on(exports.Events.ContextMenu, (event, d) => {
7843
7916
  if (this.dragging) {
7844
7917
  event.preventDefault();
7845
7918
  event.stopPropagation();
@@ -7849,8 +7922,15 @@ class DiagramCanvas {
7849
7922
  const diagramEvent = new DiagramSecondaryClickEvent(event, d);
7850
7923
  this.diagramEvent$.next(diagramEvent);
7851
7924
  if (!diagramEvent.defaultPrevented && this.canUserPerformAction(exports.DiagramActions.ContextMenu)) {
7852
- event.preventDefault();
7853
- this.contextMenu.open(event);
7925
+ if (d.rootElement) {
7926
+ event.preventDefault();
7927
+ const elementToSelect = getRelatedNodeOrItself(d.rootElement);
7928
+ this.userHighlight.focusOn(elementToSelect);
7929
+ this.diagramEvent$.next(new DiagramHighlightedEvent(elementToSelect));
7930
+ this.userSelection.add(elementToSelect);
7931
+ this.diagramEvent$.next(new DiagramSelectionEvent([elementToSelect], true));
7932
+ this.contextMenu.open(event);
7933
+ }
7854
7934
  }
7855
7935
  }).on(exports.Events.DoubleClick, (event, d) => {
7856
7936
  const diagramEvent = new DiagramDoubleClickEvent(event, d);
@@ -8324,18 +8404,18 @@ class DiagramCanvas {
8324
8404
  }
8325
8405
  startMultipleSelection(event) {
8326
8406
  this.draggingFrom = this.getPointerLocationRelativeToCanvas(event);
8327
- /* TODO: would be a good idea to build the multipleSelectionContainer
8328
- * from selectRoot() instead of selectCanvasElements()
8329
- * to avoid having the thickness of the rectangle be affected by zoom
8330
- */
8331
- this.multipleSelectionContainer = this.selectCanvasElements().append('rect').attr('stroke', '#0E74B6').attr('fill', 'rgba(14, 116, 182, 0.06)');
8407
+ // we put the multiple selection rectangle in the diagram svg element
8408
+ // so it's not affected by the zoom level in the diagram elements
8409
+ this.multipleSelectionContainer = this.selectSVGElement().append('rect').attr('stroke', '#0E74B6').attr('fill', 'rgba(14, 116, 182, 0.06)');
8332
8410
  }
8333
8411
  continueMultipleSelection(event) {
8334
8412
  var _a, _b, _c, _d;
8335
8413
  const pointerCoords = this.getPointerLocationRelativeToCanvas(event);
8336
8414
  if (this.draggingFrom[0] !== pointerCoords[0] || this.draggingFrom[1] !== pointerCoords[1]) {
8337
8415
  setCursorStyle(exports.CursorStyle.Crosshair);
8338
- (_d = (_c = (_b = (_a = this.multipleSelectionContainer) === null || _a === undefined ? undefined : _a.attr('x', Math.min(this.draggingFrom[0], pointerCoords[0]))) === null || _b === undefined ? undefined : _b.attr('y', Math.min(this.draggingFrom[1], pointerCoords[1]))) === null || _c === undefined ? undefined : _c.attr('width', Math.abs(this.draggingFrom[0] - pointerCoords[0]))) === null || _d === undefined ? undefined : _d.attr('height', Math.abs(this.draggingFrom[1] - pointerCoords[1]));
8416
+ // since the multiple selection rectangle is not affected by zoom,
8417
+ // we compensate its coordinates based in the zoom transform to draw it
8418
+ (_d = (_c = (_b = (_a = this.multipleSelectionContainer) === null || _a === undefined ? undefined : _a.attr('x', Math.min(this.draggingFrom[0], pointerCoords[0]) * this.zoomTransform.k + this.zoomTransform.x)) === null || _b === undefined ? undefined : _b.attr('y', Math.min(this.draggingFrom[1], pointerCoords[1]) * this.zoomTransform.k + this.zoomTransform.y)) === null || _c === undefined ? undefined : _c.attr('width', Math.abs(this.draggingFrom[0] - pointerCoords[0]) * this.zoomTransform.k)) === null || _d === undefined ? undefined : _d.attr('height', Math.abs(this.draggingFrom[1] - pointerCoords[1]) * this.zoomTransform.k);
8339
8419
  this.dragging = true;
8340
8420
  }
8341
8421
  }