@api-client/ui 0.2.2 → 0.2.3

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 (170) hide show
  1. package/package.json +7 -2
  2. package/test/env.ts +15 -0
  3. package/test/tsconfig.json +1 -7
  4. package/web-test-runner.config.js +5 -1
  5. package/build/src/visualization/elements/VizAssociationElement.d.ts +0 -4
  6. package/build/src/visualization/elements/VizAssociationElement.d.ts.map +0 -1
  7. package/build/src/visualization/elements/VizAssociationElement.js +0 -4
  8. package/build/src/visualization/elements/VizAssociationElement.js.map +0 -1
  9. package/build/src/visualization/elements/VizWorkspaceElement.d.ts +0 -110
  10. package/build/src/visualization/elements/VizWorkspaceElement.d.ts.map +0 -1
  11. package/build/src/visualization/elements/VizWorkspaceElement.js +0 -321
  12. package/build/src/visualization/elements/VizWorkspaceElement.js.map +0 -1
  13. package/build/src/visualization/elements/WorkspaceStyles.d.ts +0 -3
  14. package/build/src/visualization/elements/WorkspaceStyles.d.ts.map +0 -1
  15. package/build/src/visualization/elements/WorkspaceStyles.js +0 -168
  16. package/build/src/visualization/elements/WorkspaceStyles.js.map +0 -1
  17. package/build/src/visualization/lib/AnchorFinder.d.ts +0 -64
  18. package/build/src/visualization/lib/AnchorFinder.d.ts.map +0 -1
  19. package/build/src/visualization/lib/AnchorFinder.js +0 -107
  20. package/build/src/visualization/lib/AnchorFinder.js.map +0 -1
  21. package/build/src/visualization/lib/AnchorUtils.d.ts +0 -10
  22. package/build/src/visualization/lib/AnchorUtils.d.ts.map +0 -1
  23. package/build/src/visualization/lib/AnchorUtils.js +0 -44
  24. package/build/src/visualization/lib/AnchorUtils.js.map +0 -1
  25. package/build/src/visualization/lib/AssociationAnchors.d.ts +0 -134
  26. package/build/src/visualization/lib/AssociationAnchors.d.ts.map +0 -1
  27. package/build/src/visualization/lib/AssociationAnchors.js +0 -351
  28. package/build/src/visualization/lib/AssociationAnchors.js.map +0 -1
  29. package/build/src/visualization/lib/LabelSketch.d.ts +0 -16
  30. package/build/src/visualization/lib/LabelSketch.d.ts.map +0 -1
  31. package/build/src/visualization/lib/LabelSketch.js +0 -53
  32. package/build/src/visualization/lib/LabelSketch.js.map +0 -1
  33. package/build/src/visualization/lib/LineSketch.d.ts +0 -26
  34. package/build/src/visualization/lib/LineSketch.d.ts.map +0 -1
  35. package/build/src/visualization/lib/LineSketch.js +0 -55
  36. package/build/src/visualization/lib/LineSketch.js.map +0 -1
  37. package/build/src/visualization/lib/Point.d.ts +0 -74
  38. package/build/src/visualization/lib/Point.d.ts.map +0 -1
  39. package/build/src/visualization/lib/Point.js +0 -121
  40. package/build/src/visualization/lib/Point.js.map +0 -1
  41. package/build/src/visualization/lib/PositionUtils.d.ts +0 -65
  42. package/build/src/visualization/lib/PositionUtils.d.ts.map +0 -1
  43. package/build/src/visualization/lib/PositionUtils.js +0 -205
  44. package/build/src/visualization/lib/PositionUtils.js.map +0 -1
  45. package/build/src/visualization/lib/SelectionManager.d.ts +0 -183
  46. package/build/src/visualization/lib/SelectionManager.d.ts.map +0 -1
  47. package/build/src/visualization/lib/SelectionManager.js +0 -481
  48. package/build/src/visualization/lib/SelectionManager.js.map +0 -1
  49. package/build/src/visualization/lib/ShapeArtist.d.ts +0 -45
  50. package/build/src/visualization/lib/ShapeArtist.d.ts.map +0 -1
  51. package/build/src/visualization/lib/ShapeArtist.js +0 -209
  52. package/build/src/visualization/lib/ShapeArtist.js.map +0 -1
  53. package/build/src/visualization/lib/SvgMarkers.d.ts +0 -14
  54. package/build/src/visualization/lib/SvgMarkers.d.ts.map +0 -1
  55. package/build/src/visualization/lib/SvgMarkers.js +0 -77
  56. package/build/src/visualization/lib/SvgMarkers.js.map +0 -1
  57. package/build/src/visualization/lib/TipSketch.d.ts +0 -26
  58. package/build/src/visualization/lib/TipSketch.d.ts.map +0 -1
  59. package/build/src/visualization/lib/TipSketch.js +0 -77
  60. package/build/src/visualization/lib/TipSketch.js.map +0 -1
  61. package/build/src/visualization/lib/TouchSupport.d.ts +0 -14
  62. package/build/src/visualization/lib/TouchSupport.d.ts.map +0 -1
  63. package/build/src/visualization/lib/TouchSupport.js +0 -55
  64. package/build/src/visualization/lib/TouchSupport.js.map +0 -1
  65. package/build/src/visualization/lib/Utils.d.ts +0 -25
  66. package/build/src/visualization/lib/Utils.d.ts.map +0 -1
  67. package/build/src/visualization/lib/Utils.js +0 -59
  68. package/build/src/visualization/lib/Utils.js.map +0 -1
  69. package/build/src/visualization/lib/VisualizationTypes.d.ts +0 -216
  70. package/build/src/visualization/lib/VisualizationTypes.d.ts.map +0 -1
  71. package/build/src/visualization/lib/VisualizationTypes.js +0 -3
  72. package/build/src/visualization/lib/VisualizationTypes.js.map +0 -1
  73. package/build/src/visualization/lib/WorkspaceAlignment.d.ts +0 -51
  74. package/build/src/visualization/lib/WorkspaceAlignment.d.ts.map +0 -1
  75. package/build/src/visualization/lib/WorkspaceAlignment.js +0 -243
  76. package/build/src/visualization/lib/WorkspaceAlignment.js.map +0 -1
  77. package/build/src/visualization/lib/WorkspaceDebugging.d.ts +0 -104
  78. package/build/src/visualization/lib/WorkspaceDebugging.d.ts.map +0 -1
  79. package/build/src/visualization/lib/WorkspaceDebugging.js +0 -286
  80. package/build/src/visualization/lib/WorkspaceDebugging.js.map +0 -1
  81. package/build/src/visualization/lib/WorkspaceEdges.d.ts +0 -293
  82. package/build/src/visualization/lib/WorkspaceEdges.d.ts.map +0 -1
  83. package/build/src/visualization/lib/WorkspaceEdges.js +0 -1073
  84. package/build/src/visualization/lib/WorkspaceEdges.js.map +0 -1
  85. package/build/src/visualization/lib/WorkspaceGestures.d.ts +0 -119
  86. package/build/src/visualization/lib/WorkspaceGestures.d.ts.map +0 -1
  87. package/build/src/visualization/lib/WorkspaceGestures.js +0 -376
  88. package/build/src/visualization/lib/WorkspaceGestures.js.map +0 -1
  89. package/build/src/visualization/lib/WorkspaceSizing.d.ts +0 -66
  90. package/build/src/visualization/lib/WorkspaceSizing.d.ts.map +0 -1
  91. package/build/src/visualization/lib/WorkspaceSizing.js +0 -168
  92. package/build/src/visualization/lib/WorkspaceSizing.js.map +0 -1
  93. package/build/src/visualization/lib/lines/RectilinearLine.d.ts +0 -114
  94. package/build/src/visualization/lib/lines/RectilinearLine.d.ts.map +0 -1
  95. package/build/src/visualization/lib/lines/RectilinearLine.js +0 -605
  96. package/build/src/visualization/lib/lines/RectilinearLine.js.map +0 -1
  97. package/build/src/visualization/lib/tips/RectilinearTip.d.ts +0 -26
  98. package/build/src/visualization/lib/tips/RectilinearTip.d.ts.map +0 -1
  99. package/build/src/visualization/lib/tips/RectilinearTip.js +0 -149
  100. package/build/src/visualization/lib/tips/RectilinearTip.js.map +0 -1
  101. package/build/src/visualization/lib/tips/TipArtist.d.ts +0 -22
  102. package/build/src/visualization/lib/tips/TipArtist.d.ts.map +0 -1
  103. package/build/src/visualization/lib/tips/TipArtist.js +0 -31
  104. package/build/src/visualization/lib/tips/TipArtist.js.map +0 -1
  105. package/build/src/visualization/lib/types.d.ts +0 -164
  106. package/build/src/visualization/lib/types.d.ts.map +0 -1
  107. package/build/src/visualization/lib/types.js +0 -2
  108. package/build/src/visualization/lib/types.js.map +0 -1
  109. package/build/src/visualization/plugin/dnd/DragAndDropPlugin.d.ts +0 -126
  110. package/build/src/visualization/plugin/dnd/DragAndDropPlugin.d.ts.map +0 -1
  111. package/build/src/visualization/plugin/dnd/DragAndDropPlugin.js +0 -260
  112. package/build/src/visualization/plugin/dnd/DragAndDropPlugin.js.map +0 -1
  113. package/build/src/visualization/plugin/group-selection/GroupSelection.d.ts +0 -93
  114. package/build/src/visualization/plugin/group-selection/GroupSelection.d.ts.map +0 -1
  115. package/build/src/visualization/plugin/group-selection/GroupSelection.js +0 -250
  116. package/build/src/visualization/plugin/group-selection/GroupSelection.js.map +0 -1
  117. package/build/src/visualization/plugin/positioning/DataModelLayout.d.ts +0 -10
  118. package/build/src/visualization/plugin/positioning/DataModelLayout.d.ts.map +0 -1
  119. package/build/src/visualization/plugin/positioning/DataModelLayout.js +0 -105
  120. package/build/src/visualization/plugin/positioning/DataModelLayout.js.map +0 -1
  121. package/build/src/visualization/plugin/positioning/WorkspaceLayout.d.ts +0 -93
  122. package/build/src/visualization/plugin/positioning/WorkspaceLayout.d.ts.map +0 -1
  123. package/build/src/visualization/plugin/positioning/WorkspaceLayout.js +0 -96
  124. package/build/src/visualization/plugin/positioning/WorkspaceLayout.js.map +0 -1
  125. package/build/src/visualization/viz-association.d.ts +0 -7
  126. package/build/src/visualization/viz-association.d.ts.map +0 -1
  127. package/build/src/visualization/viz-association.js +0 -3
  128. package/build/src/visualization/viz-association.js.map +0 -1
  129. package/build/src/visualization/viz-workspace.d.ts +0 -7
  130. package/build/src/visualization/viz-workspace.d.ts.map +0 -1
  131. package/build/src/visualization/viz-workspace.js +0 -3
  132. package/build/src/visualization/viz-workspace.js.map +0 -1
  133. package/src/visualization/elements/VizAssociationElement.ts +0 -3
  134. package/src/visualization/elements/VizWorkspaceElement.ts +0 -302
  135. package/src/visualization/elements/WorkspaceStyles.ts +0 -168
  136. package/src/visualization/lib/AnchorFinder.ts +0 -112
  137. package/src/visualization/lib/AnchorUtils.ts +0 -53
  138. package/src/visualization/lib/AssociationAnchors.ts +0 -418
  139. package/src/visualization/lib/LabelSketch.ts +0 -67
  140. package/src/visualization/lib/LineSketch.ts +0 -62
  141. package/src/visualization/lib/Point.ts +0 -134
  142. package/src/visualization/lib/PositionUtils.ts +0 -218
  143. package/src/visualization/lib/SelectionManager.ts +0 -513
  144. package/src/visualization/lib/ShapeArtist.ts +0 -222
  145. package/src/visualization/lib/SvgMarkers.ts +0 -80
  146. package/src/visualization/lib/TipSketch.ts +0 -91
  147. package/src/visualization/lib/TouchSupport.ts +0 -72
  148. package/src/visualization/lib/Utils.ts +0 -63
  149. package/src/visualization/lib/VisualizationTypes.ts +0 -232
  150. package/src/visualization/lib/WorkspaceAlignment.ts +0 -261
  151. package/src/visualization/lib/WorkspaceDebugging.ts +0 -313
  152. package/src/visualization/lib/WorkspaceEdges.ts +0 -1153
  153. package/src/visualization/lib/WorkspaceGestures.ts +0 -400
  154. package/src/visualization/lib/WorkspaceSizing.ts +0 -181
  155. package/src/visualization/lib/lines/RectilinearLine.ts +0 -589
  156. package/src/visualization/lib/tips/RectilinearTip.ts +0 -156
  157. package/src/visualization/lib/tips/TipArtist.ts +0 -34
  158. package/src/visualization/lib/types.ts +0 -173
  159. package/src/visualization/plugin/dnd/DragAndDropPlugin.ts +0 -294
  160. package/src/visualization/plugin/group-selection/GroupSelection.ts +0 -271
  161. package/src/visualization/plugin/positioning/DataModelLayout.ts +0 -114
  162. package/src/visualization/plugin/positioning/WorkspaceLayout.ts +0 -149
  163. package/src/visualization/viz-association.ts +0 -9
  164. package/src/visualization/viz-workspace.ts +0 -9
  165. package/test/env.d.ts +0 -9
  166. package/test/env.js +0 -7
  167. package/test/visualization/lib/AnchorFinder.test.ts +0 -313
  168. package/test/visualization/lib/AnchorUtils.test.ts +0 -178
  169. package/test/visualization/lib/PositionUtils.test.ts +0 -406
  170. package/test/visualization/lib/test-styles.css +0 -80
@@ -1,1153 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-unused-vars */
2
- import { getObjectBoundingClientRect, findDirection } from './PositionUtils.js'
3
- import { closestAnchors, anchorToPoint } from './AnchorUtils.js'
4
- import { LineSketch } from './LineSketch.js'
5
- import { TipSketch } from './TipSketch.js'
6
- import { LabelSketch } from './LabelSketch.js'
7
- import { anchorPadding, findClosestAnchors } from './AnchorFinder.js'
8
- import { ICalculateEdgeOptions, IEdgeDirections, IWorkspaceEdge } from './types.js'
9
- import VizWorkspaceElement from '../elements/VizWorkspaceElement.js'
10
- import VizAssociationElement from '../elements/VizAssociationElement.js'
11
- import {
12
- IAssociationShape,
13
- IAssociationSlots,
14
- IAssociationVertexes,
15
- ILineTips,
16
- IVisualizationAssociationShape,
17
- IVisualizationRectilinearLineShape,
18
- } from './VisualizationTypes.js'
19
- import { Point } from './Point.js'
20
-
21
- const DefaultLineType = 'rectilinear'
22
-
23
- export const observeItems = Symbol('observeItems')
24
- export const clickHandler = Symbol('clickHandler')
25
- export const mouseOverHandler = Symbol('mouseOverHandler')
26
- export const mouseOutHandler = Symbol('mouseOutHandler')
27
- export const mutationHandler = Symbol('mutationHandler')
28
- export const mutationObserver = Symbol('mutationObserver')
29
- export const processAddedNodes = Symbol('processAddedNodes')
30
- export const processRemovedNodes = Symbol('processRemovedNodes')
31
- export const processAttributeChanged = Symbol('processAttributeChanged')
32
- export const connectedValue = Symbol('connectedValue')
33
- export const processAddedAssociation = Symbol('processAddedAssociation')
34
- export const processRemovedAssociation = Symbol('processRemovedAssociation')
35
- export const processAddedNode = Symbol('processAddedNode')
36
- export const processRemovedNode = Symbol('processRemovedNode')
37
- export const edgesValue = Symbol('edgesValue')
38
- export const associationClickHandler = Symbol('associationClickHandler')
39
- export const deselectAllEdges = Symbol('deselectAllEdges')
40
- export const calculateEdge = Symbol('calculateEdge')
41
- export const processQueue = Symbol('processQueue')
42
- export const processQueueDebouncer = Symbol('processQueueDebouncer')
43
- export const updateAssociationById = Symbol('updateAssociationById')
44
- export const calculateNearestPoints = Symbol('calculateNearestPoints')
45
- export const readEventTarget = Symbol('readEventTarget')
46
-
47
- /**
48
- * A class that manages drawing edges between the nodes in the workspace visualization.
49
- *
50
- * This class looks for the `viz-association` elements inside other elements
51
- * and when the association has a valid (existing) target then it creates an internal model for the edge
52
- * visualization and sets it on the workspace to be rendered.
53
- *
54
- * This class also manages selection state of the edge.
55
- */
56
- export class WorkspaceEdges {
57
- [connectedValue] = false
58
-
59
- /**
60
- * @returns True when the plug-in is listening for the input events.
61
- */
62
- get connected(): boolean {
63
- return this[connectedValue]
64
- }
65
-
66
- [edgesValue]: Map<string, IWorkspaceEdge> = new Map<string, IWorkspaceEdge>()
67
-
68
- /**
69
- * @returns The edges to be visualized in the workspace.
70
- */
71
- get edges(): Map<string, IWorkspaceEdge> {
72
- return this[edgesValue]
73
- }
74
-
75
- /**
76
- * When an association is changed in the DOM it is held in this array to process them asynchronously
77
- * in the future, when the workspace is updated.
78
- */
79
- [processQueue]: VizAssociationElement[] = []
80
-
81
- /**
82
- * The processor used to draw lines
83
- */
84
- lineProcessor = new LineSketch()
85
-
86
- /**
87
- * The processor used to draw tips on the line
88
- */
89
- tipProcessor = new TipSketch();
90
-
91
- [mutationObserver]?: MutationObserver
92
-
93
- constructor(public workspace: VizWorkspaceElement) {
94
- this[mutationHandler] = this[mutationHandler].bind(this)
95
- this[clickHandler] = this[clickHandler].bind(this)
96
- this[mouseOverHandler] = this[mouseOverHandler].bind(this)
97
- this[mouseOutHandler] = this[mouseOutHandler].bind(this)
98
- }
99
-
100
- /**
101
- * Starts listening on user events
102
- */
103
- connect(): void {
104
- this[mutationObserver] = this[observeItems]()
105
- this[connectedValue] = true
106
- if (this.workspace.associationSvg) {
107
- this.listenContent()
108
- }
109
- this.associateCurrent()
110
- }
111
-
112
- /**
113
- * Creates associations for the current state of the canvas.
114
- */
115
- associateCurrent(): void {
116
- const nodes = Array.from(this.workspace.querySelectorAll('viz-association')) as VizAssociationElement[]
117
- nodes.forEach((assoc) => this[processAddedAssociation](assoc))
118
- }
119
-
120
- /**
121
- * Initializes events when the workspace DOM is rendered.
122
- */
123
- listenContent(): void {
124
- this.workspace.associationSvg.addEventListener('click', this[clickHandler] as EventListener)
125
- this.workspace.associationSvg.addEventListener('mouseover', this[mouseOverHandler])
126
- this.workspace.associationSvg.addEventListener('mouseout', this[mouseOutHandler])
127
- }
128
-
129
- /**
130
- * Cleans up the listeners
131
- */
132
- disconnect(): void {
133
- const observer = this[mutationObserver]
134
- if (observer) {
135
- observer.disconnect()
136
- this[mutationObserver] = undefined
137
- }
138
- this[connectedValue] = false
139
- this.workspace.associationSvg.removeEventListener('click', this[clickHandler] as EventListener)
140
- this.workspace.associationSvg.removeEventListener('mouseover', this[mouseOverHandler])
141
- this.workspace.associationSvg.removeEventListener('mouseout', this[mouseOutHandler])
142
- }
143
-
144
- /**
145
- * Clear all edges from the workspace
146
- */
147
- clear(): void {
148
- this[edgesValue].clear()
149
- this.workspace.requestUpdate()
150
- }
151
-
152
- /**
153
- * Forces to re-calculate all existing edges.
154
- */
155
- async recalculate(): Promise<void> {
156
- const { edges, workspace } = this
157
- edges.forEach((edge) => {
158
- const { id, source, target, shape } = edge
159
- const { label } = shape
160
- const item = this[updateAssociationById](source, target, id, label && label.value)
161
- if (item) {
162
- edges.set(id, item)
163
- }
164
- })
165
- workspace.requestUpdate()
166
- }
167
-
168
- /**
169
- * Reads an edge definition by the association id.
170
- */
171
- get(key: string): IWorkspaceEdge | undefined {
172
- const { edges } = this
173
- return edges.get(key)
174
- }
175
-
176
- /**
177
- * Removes an edge and notifies workspace to update.
178
- */
179
- removeEdge(id: string): void {
180
- if (this[edgesValue].has(id)) {
181
- this[edgesValue].delete(id)
182
- this.workspace.requestUpdate()
183
- }
184
- }
185
-
186
- /**
187
- * Updates associations (in and out) for an element identified by the `key` attribute.
188
- * The element must be one of the visualized elements in the workspace.
189
- *
190
- * This is to be used when position and or size of an element that has associations change.
191
- *
192
- * @param key The domain id of the visualized element that has changed.
193
- */
194
- async update(key: string): Promise<void> {
195
- const { edges, workspace } = this
196
- const element = workspace.querySelector(`[data-key="${key}"]`)
197
- if (!element) {
198
- return
199
- }
200
- edges.forEach((edge) => {
201
- const { source, target, id, shape } = edge
202
- const { label } = shape
203
- let change = false
204
- if ([source, target].includes(key)) {
205
- change = true
206
- }
207
- if (change) {
208
- const item = this[updateAssociationById](source, target, id, label && label.value)
209
- if (item) {
210
- edges.set(id, item)
211
- }
212
- }
213
- })
214
- workspace.requestUpdate()
215
- await workspace.updateComplete
216
- }
217
-
218
- /**
219
- * Computes workspace edge object for source and target.
220
- *
221
- * @param source The domain id of the source element
222
- * @param target The domain id of the target element
223
- * @param id The domain id of the association
224
- * @param name The label rendered in the association
225
- */
226
- [updateAssociationById](source: string, target: string, id: string, name?: string): IWorkspaceEdge | null {
227
- const { workspace } = this
228
- const sourceElement = workspace.querySelector(`[data-key="${source}"]`) as HTMLElement
229
- if (!sourceElement) {
230
- return null
231
- }
232
- const targetElement = workspace.querySelector(`[data-key="${target}"]`) as HTMLElement
233
- if (!targetElement) {
234
- return null
235
- }
236
- const opts: ICalculateEdgeOptions = {
237
- sourceElement,
238
- targetElement,
239
- id,
240
- name,
241
- }
242
- const assocElement = workspace.querySelector(`viz-association[data-key="${id}"]`) as VizAssociationElement | null
243
- if (!assocElement) {
244
- return null
245
- }
246
- const slots = this.readAssociationSlots(assocElement)
247
- if (slots.source) {
248
- opts.sourceSlot = slots.source
249
- }
250
- if (slots.target) {
251
- opts.targetSlot = slots.target
252
- }
253
- const others = this.findOtherAssociations(sourceElement, targetElement, assocElement.dataset.key as string)
254
- if (others.length) {
255
- opts.others = others
256
- }
257
- return this[calculateEdge](opts) || null
258
- }
259
-
260
- /**
261
- * Creates a internal data model for the edge drawn between an association source and the target.
262
- * @param assocElement The viz-association element reference
263
- * @param targetElement The target element reference.
264
- */
265
- buildAssociationEdge(assocElement: VizAssociationElement, targetElement: HTMLElement): void {
266
- const sourceElement = assocElement.parentElement as HTMLElement
267
- if (!sourceElement || !sourceElement.dataset.key) {
268
- return
269
- }
270
- const slots = this.readAssociationSlots(assocElement)
271
- const { title, dataset } = assocElement
272
- const opts: ICalculateEdgeOptions = {
273
- sourceElement,
274
- targetElement,
275
- id: dataset.key as string,
276
- name: title || '',
277
- }
278
- if (slots.source) {
279
- opts.sourceSlot = slots.source
280
- }
281
- if (slots.target) {
282
- opts.targetSlot = slots.target
283
- }
284
- const map = this[edgesValue]
285
- const others = this.findOtherAssociations(sourceElement, targetElement, dataset.key as string)
286
- if (others.length) {
287
- opts.others = others
288
- }
289
- const item = this[calculateEdge](opts)
290
- if (item) {
291
- map.set(dataset.key as string, item)
292
- }
293
- this.workspace.requestUpdate()
294
- }
295
-
296
- /**
297
- */
298
- findOtherAssociations(sourceElement: HTMLElement, targetElement: HTMLElement, assocId: string): IWorkspaceEdge[] {
299
- const srcId = sourceElement.dataset.key as string
300
- const trgId = targetElement.dataset.key as string
301
- const sourceAssociations = Array.from(sourceElement.querySelectorAll('viz-association')) as HTMLElement[]
302
- const targetAssociations = Array.from(sourceElement.querySelectorAll('viz-association')) as HTMLElement[]
303
- const otherSourceAssociations = sourceAssociations.filter(
304
- (i) => i.dataset.target === trgId && i.dataset.key !== assocId
305
- )
306
- const otherTargetAssociations = targetAssociations.filter((i) => i.dataset.target === srcId && i.dataset.key)
307
- const others: IWorkspaceEdge[] = []
308
- const map = this[edgesValue]
309
- otherSourceAssociations.concat(otherTargetAssociations).forEach((item) => {
310
- const m = map.get(item.dataset.key as string)
311
- if (m) {
312
- others.push(m)
313
- }
314
- })
315
- return others
316
- }
317
-
318
- /**
319
- * Reads the view model for an association and returns slot definitions for the association.
320
- *
321
- * @param assocElement The viz-association element reference
322
- */
323
- readAssociationSlots(assocElement: VizAssociationElement): IAssociationSlots {
324
- const result: IAssociationSlots = {}
325
- Array.from(assocElement.querySelectorAll('modeling-view')).forEach((item) => {
326
- // if (item.name === 'sourceSlot') {
327
- // result.source = item.value;
328
- // } else if (item.name === 'targetSlot') {
329
- // result.target = item.value;
330
- // }
331
- })
332
- return result
333
- }
334
-
335
- /**
336
- * Calculates the edge between two nodes.
337
- */
338
- [calculateNearestPoints](
339
- sourceElement: HTMLElement,
340
- targetElement: HTMLElement,
341
- others?: IWorkspaceEdge[]
342
- ): Point[] | null {
343
- const { workspace } = this
344
- if (sourceElement.hasAttribute('data-association-slots') && targetElement.hasAttribute('data-association-slots')) {
345
- return closestAnchors(sourceElement, targetElement, workspace, others)
346
- }
347
- const sourceBox = getObjectBoundingClientRect(sourceElement, workspace)
348
- const targetBox = getObjectBoundingClientRect(targetElement, workspace)
349
- const anchors = findClosestAnchors(sourceBox, targetBox, anchorPadding)
350
- return anchors
351
- }
352
-
353
- /**
354
- * Calculates the edge between two nodes.
355
- */
356
- [calculateEdge](options: ICalculateEdgeOptions): IWorkspaceEdge | undefined {
357
- const { sourceElement, targetElement, id, name = '' } = options
358
- const slotPoints = this.discoverAssociationVertexes(options)
359
- if (!slotPoints) {
360
- return undefined
361
- }
362
- const sourceRect = getObjectBoundingClientRect(sourceElement, this.workspace)
363
- const targetRect = getObjectBoundingClientRect(targetElement, this.workspace)
364
- const sketch = this.lineProcessor.sketch({
365
- source: sourceRect,
366
- target: targetRect,
367
- startPoint: slotPoints.start as Point,
368
- endPoint: slotPoints.end as Point,
369
- type: DefaultLineType,
370
- others: options.others,
371
- }) as IVisualizationRectilinearLineShape
372
- if (!sketch) {
373
- return undefined
374
- }
375
- const coords = sketch.coordinates as Point[]
376
- const [sp] = coords
377
- const ep = coords[coords.length - 1]
378
- const directions = findDirection(sp, ep, sourceRect, targetRect)
379
-
380
- const labelArtist = new LabelSketch()
381
- const label = labelArtist.sketch(sketch, name, directions) || undefined
382
- const assocElement = this.workspace.querySelector(`viz-association[data-key="${id}"]`) as HTMLElement
383
- const style = this.createAssociationStyles(assocElement)
384
- const tips = this.createAssociationTips(assocElement, sketch, directions)
385
- const positionChange =
386
- sourceElement.hasAttribute('data-association-slots') && targetElement.hasAttribute('data-association-slots')
387
-
388
- const shape: IAssociationShape = {
389
- selection: {
390
- primary: false,
391
- secondary: false,
392
- },
393
- line: sketch,
394
- style,
395
- label,
396
- tips,
397
- }
398
- const srcId = sourceElement.dataset.key
399
- const trgId = targetElement.dataset.key
400
- if (!srcId || !trgId) {
401
- return undefined
402
- }
403
- const positionItem: IWorkspaceEdge = {
404
- id,
405
- source: srcId,
406
- target: trgId,
407
- positionChange,
408
- directions,
409
- shape,
410
- }
411
- if (options.sourceSlot || options.targetSlot) {
412
- shape.slots = {}
413
- if (options.sourceSlot) {
414
- shape.slots.source = options.sourceSlot
415
- }
416
- if (options.targetSlot) {
417
- shape.slots.target = options.targetSlot
418
- }
419
- }
420
- return positionItem
421
- }
422
-
423
- discoverAssociationVertexes(options: ICalculateEdgeOptions): IAssociationVertexes | undefined {
424
- const slotPoints = (this.discoverSlotPoints(options) || {}) as IAssociationVertexes
425
- if (!slotPoints.end || !slotPoints.start) {
426
- const closest = this[calculateNearestPoints](
427
- options.sourceElement,
428
- options.targetElement,
429
- options.others as IWorkspaceEdge[]
430
- )
431
- if (!closest) {
432
- return undefined
433
- }
434
- if (!slotPoints.start) {
435
- slotPoints.start = closest[0]
436
- }
437
- if (!slotPoints.end) {
438
- slotPoints.end = closest[1]
439
- }
440
- }
441
- return slotPoints
442
- }
443
-
444
- /**
445
- * When defined and correctly configured it returns position of the slots of the source and the target.
446
- */
447
- discoverSlotPoints(options: ICalculateEdgeOptions): IAssociationVertexes | undefined {
448
- const { sourceElement, targetElement, sourceSlot, targetSlot } = options
449
- if (!sourceSlot && !targetSlot) {
450
- return undefined
451
- }
452
- const result: IAssociationVertexes = {}
453
- if (sourceSlot) {
454
- const dom = sourceElement.shadowRoot ? sourceElement.shadowRoot : sourceElement
455
- const obj = dom.querySelector(`[data-association-slot="${sourceSlot}"]`) as HTMLElement
456
- if (obj) {
457
- result.start = anchorToPoint(obj, this.workspace)
458
- }
459
- }
460
- if (targetElement) {
461
- const dom = targetElement.shadowRoot ? targetElement.shadowRoot : targetElement
462
- const obj = dom.querySelector(`[data-association-slot="${targetSlot}"]`) as HTMLElement
463
- if (obj) {
464
- result.end = anchorToPoint(obj, this.workspace)
465
- }
466
- }
467
- return result
468
- }
469
-
470
- /**
471
- * Creates edge's markers definition from the association element.
472
- * The association element can have the following attributes set:
473
- * - data-marker-end
474
- * - data-marker-start
475
- * With a value of a marker name defined in the visualization workspace.
476
- *
477
- * @param assocElement The association element to read the values from.
478
- * @param lineShape The definition of the line that the marker is attached to
479
- * @param directions Computed line directions
480
- */
481
- createAssociationTips(
482
- assocElement: HTMLElement,
483
- lineShape: IVisualizationAssociationShape,
484
- directions: IEdgeDirections
485
- ): ILineTips {
486
- const result: ILineTips = {}
487
- if (!assocElement) {
488
- return result
489
- }
490
- const { dataset } = assocElement
491
- const { markerEnd, markerStart } = dataset
492
- const style = this.createAssociationStyles(assocElement)
493
- if (markerEnd) {
494
- // result.end = this.buildEdgeTip(markerEnd, lineShape, directions);
495
- result.end = this.tipProcessor.endMarker(markerEnd, lineShape, directions)
496
- if (style) {
497
- result.end.style = style
498
- }
499
- }
500
- if (markerStart) {
501
- // result.start = this.buildEdgeTip(markerStart, lineShape, directions);
502
- result.start = this.tipProcessor.startMarker(markerStart, lineShape, directions)
503
- if (style) {
504
- result.start.style = style
505
- }
506
- }
507
- return result
508
- }
509
-
510
- /**
511
- * Reads element's `data-style` attribute and returns it.
512
- * This is used in the edge definition for class name.
513
- *
514
- * @param assocElement The association element to read the values from.
515
- */
516
- createAssociationStyles(assocElement: HTMLElement): string {
517
- let result = ''
518
- if (assocElement) {
519
- const { dataset } = assocElement
520
- const { style } = dataset
521
- if (style) {
522
- result = style
523
- }
524
- }
525
- return result
526
- }
527
-
528
- /**
529
- * Updates an existing association data model for position
530
- * @param assocElement The viz-association element reference
531
- * @param targetElement The target element reference.
532
- */
533
- updateAssociationPosition(assocElement: VizAssociationElement, targetElement: HTMLElement): void {
534
- const id = assocElement.dataset.key as string
535
- const map = this[edgesValue]
536
- if (!map.has(id)) {
537
- return
538
- }
539
- const sourceElement = assocElement.parentElement as HTMLElement
540
- if (!sourceElement || !sourceElement.dataset.key) {
541
- return
542
- }
543
- const model = map.get(id)
544
- if (!model) {
545
- return
546
- }
547
- const opts: ICalculateEdgeOptions = {
548
- sourceElement,
549
- targetElement,
550
- id,
551
- }
552
-
553
- const slots = this.readAssociationSlots(assocElement)
554
- if (slots.source) {
555
- opts.sourceSlot = slots.source
556
- }
557
- if (slots.target) {
558
- opts.targetSlot = slots.target
559
- }
560
- const others = this.findOtherAssociations(sourceElement, targetElement, assocElement.dataset.key as string)
561
- if (others.length) {
562
- opts.others = others
563
- }
564
- const slotPoints = this.discoverAssociationVertexes(opts)
565
- if (!slotPoints) {
566
- return
567
- }
568
- const sourceRect = getObjectBoundingClientRect(sourceElement, this.workspace)
569
- const targetRect = getObjectBoundingClientRect(targetElement, this.workspace)
570
- const sketch = this.lineProcessor.sketch({
571
- source: sourceRect,
572
- target: targetRect,
573
- startPoint: slotPoints.start as Point,
574
- endPoint: slotPoints.end as Point,
575
- type: model.shape.line.type || DefaultLineType,
576
- }) as IVisualizationAssociationShape
577
- if (!sketch) {
578
- return
579
- }
580
- const coord = sketch.coordinates as Point[]
581
- const [sp] = coord
582
- const ep = coord[coord.length - 1]
583
- const directions = findDirection(sp, ep, sourceRect, targetRect)
584
-
585
- const labelArtist = new LabelSketch()
586
- const label = labelArtist.sketch(sketch, (model.shape.label && model.shape.label.value) || '', directions)
587
- const tips = this.createAssociationTips(assocElement, sketch, directions)
588
-
589
- model.shape.line = sketch
590
- model.shape.label = label || undefined
591
- model.shape.tips = tips
592
- model.directions = directions
593
- this.workspace.requestUpdate()
594
- }
595
-
596
- /**
597
- * Updates the label of the association in the visualization canvas.
598
- *
599
- * @param assocElement The viz-association element reference
600
- */
601
- updateAssociationLabel(assocElement: VizAssociationElement): void {
602
- const map = this[edgesValue]
603
- const key = assocElement.dataset.key as string
604
- if (!map.has(key)) {
605
- return
606
- }
607
- const { title } = assocElement
608
- const model = map.get(key) as IWorkspaceEdge
609
- if (model.shape && model.shape.label) {
610
- model.shape.label.value = title || ''
611
- this.workspace.requestUpdate()
612
- }
613
- }
614
-
615
- /**
616
- * Updates the `markers` property from an association element.
617
- *
618
- * @param assocElement The viz-association element reference
619
- */
620
- updateEdgeMarker(assocElement: VizAssociationElement): void {
621
- const map = this[edgesValue]
622
- const assocId = assocElement.dataset.key
623
- if (!assocId) {
624
- return
625
- }
626
- if (!map.has(assocId)) {
627
- return
628
- }
629
- const model = map.get(assocId) as IWorkspaceEdge
630
- const sourceElement = assocElement.parentElement as HTMLElement
631
- if (!sourceElement || !sourceElement.dataset.key) {
632
- return
633
- }
634
- const targetElement = this.findDomainTarget(model.target) as HTMLElement | undefined
635
- if (!targetElement || !targetElement.dataset.key) {
636
- return
637
- }
638
- const closest = this[calculateNearestPoints](sourceElement, targetElement)
639
- if (!closest) {
640
- return
641
- }
642
- const sourceRect = getObjectBoundingClientRect(sourceElement, this.workspace)
643
- const targetRect = getObjectBoundingClientRect(targetElement, this.workspace)
644
- const shape = this.lineProcessor.sketch({
645
- source: sourceRect,
646
- target: targetRect,
647
- startPoint: closest[0],
648
- endPoint: closest[1],
649
- type: model.shape.line.type || DefaultLineType,
650
- }) as IVisualizationAssociationShape
651
- if (!shape || !shape.coordinates) {
652
- return
653
- }
654
- const [sp] = shape.coordinates
655
- const ep = shape.coordinates[shape.coordinates.length - 1]
656
- const directions = findDirection(sp, ep, sourceRect, targetRect)
657
-
658
- const tips = this.createAssociationTips(assocElement, shape, directions)
659
- model.shape.tips = tips
660
- this.workspace.requestUpdate()
661
- }
662
-
663
- /**
664
- * Updates the `styles` property from an association element.
665
- *
666
- * @param assocElement The viz-association element reference
667
- */
668
- updateEdgeStyles(assocElement: VizAssociationElement): void {
669
- const map = this[edgesValue]
670
- const key = assocElement.dataset.key
671
- if (!key) {
672
- return
673
- }
674
- if (!map.has(key)) {
675
- return
676
- }
677
- const model = map.get(key) as IWorkspaceEdge
678
- model.shape.style = this.createAssociationStyles(assocElement)
679
- this.workspace.requestUpdate()
680
- }
681
-
682
- /**
683
- * Updates the selection state of the edge
684
- *
685
- * @param assocElement The viz-association element reference
686
- */
687
- toggleEdgeHighlight(assocElement: VizAssociationElement): void {
688
- const map = this[edgesValue]
689
- const key = assocElement.dataset.key
690
- if (!key) {
691
- return
692
- }
693
- if (!map.has(key)) {
694
- return
695
- }
696
- const model = map.get(key) as IWorkspaceEdge
697
- if (!model.shape.selection) {
698
- model.shape.selection = {}
699
- }
700
- model.shape.selection.primary = assocElement.hasAttribute('data-selected')
701
- this.workspace.requestUpdate()
702
- }
703
-
704
- /**
705
- * Updates the selection state of the edge
706
- *
707
- * @param assocElement The viz-association element reference
708
- */
709
- toggleEdgeSecondaryHighlight(assocElement: VizAssociationElement): void {
710
- const map = this[edgesValue]
711
- const key = assocElement.dataset.key
712
- if (!key) {
713
- return
714
- }
715
- if (!map.has(key)) {
716
- return
717
- }
718
- const model = map.get(key) as IWorkspaceEdge
719
- if (!model.shape.selection) {
720
- model.shape.selection = {}
721
- }
722
- model.shape.selection.secondary = assocElement.hasAttribute('secondary-selected')
723
- this.workspace.requestUpdate()
724
- }
725
-
726
- /**
727
- * Removes an association edge from the edges list.
728
- * @param associationId The domain id of the association
729
- */
730
- delete(associationId: string): void {
731
- const map = this[edgesValue]
732
- if (!map.has(associationId)) {
733
- return
734
- }
735
- map.delete(associationId)
736
- this.workspace.requestUpdate()
737
- }
738
-
739
- /**
740
- * A function that checks whether the associations reported in this class still exist in the workspace.
741
- */
742
- syncAssociations(): void {
743
- const map = this[edgesValue]
744
- const { workspace } = this
745
- let updated = false
746
- map.forEach((model) => {
747
- const { id, target } = model
748
- const node = workspace.querySelector(`viz-association[data-key="${id}"]`)
749
- if (!node) {
750
- map.delete(id)
751
- updated = true
752
- return
753
- }
754
- const targetNode = this.findDomainTarget(target)
755
- if (!targetNode) {
756
- map.delete(id)
757
- updated = true
758
- }
759
- })
760
- if (updated) {
761
- workspace.requestUpdate()
762
- }
763
- }
764
-
765
- /**
766
- * Searches the DOM for the domain element that has set the `data-key`.
767
- * It takes into the account the `data-delegate-visualization` attribute.
768
- *
769
- * @param target The domain id of the target.
770
- * @returns The domain element or null if not found.
771
- */
772
- findDomainTarget(target: string): HTMLElement | null {
773
- const targetElement = this.workspace.querySelector(`[data-key="${target}"]`) as HTMLElement | null
774
- return targetElement
775
- }
776
-
777
- [processQueueDebouncer]?: number
778
-
779
- runProcessingQueue(): void {
780
- const timeout = this[processQueueDebouncer]
781
- if (timeout) {
782
- clearTimeout(timeout)
783
- }
784
- this[processQueueDebouncer] = setTimeout(async () => {
785
- this[processQueueDebouncer] = undefined
786
- await this.workspace.updateComplete
787
- this[processQueue].forEach((assoc) => {
788
- const { target } = assoc.dataset
789
- if (!target) {
790
- return
791
- }
792
- const targetElement = this.findDomainTarget(target)
793
- if (!targetElement) {
794
- return
795
- }
796
- this.buildAssociationEdge(assoc, targetElement)
797
- })
798
- this[processQueue] = []
799
- }) as unknown as number
800
- }
801
-
802
- /**
803
- * Adds an association element to the rendering queue and runs the queue.
804
- */
805
- queueAssociation(assoc: VizAssociationElement): void {
806
- if (this[processQueue].includes(assoc)) {
807
- return
808
- }
809
- this[processQueue].push(assoc)
810
- this.runProcessingQueue()
811
- }
812
-
813
- // PRIVATE APIS
814
-
815
- /**
816
- * Observe items change in the element's light DOM
817
- * @returns The observer handler
818
- */
819
- [observeItems](): MutationObserver {
820
- const config = /** @type MutationObserverInit */ {
821
- attributes: true,
822
- childList: true,
823
- subtree: true,
824
- attributeOldValue: true,
825
- }
826
- const observer = new MutationObserver(this[mutationHandler])
827
- observer.observe(this.workspace, config)
828
- return observer
829
- }
830
-
831
- /**
832
- * Processes mutations in the workspace and manages selection state.
833
- * @param mutationsList List of mutations.
834
- */
835
- async [mutationHandler](mutationsList: MutationRecord[]): Promise<void> {
836
- await this.workspace.updateComplete
837
- for (const mutation of mutationsList) {
838
- if (mutation.type === 'childList') {
839
- this[processAddedNodes](mutation.addedNodes)
840
- this[processRemovedNodes](mutation.removedNodes)
841
- } else if (mutation.type === 'attributes') {
842
- this[processAttributeChanged](mutation)
843
- }
844
- }
845
- }
846
-
847
- /**
848
- * Processes added to the canvas elements.
849
- * @param nodes The list of added nodes
850
- */
851
- [processAddedNodes](nodes: NodeList): void {
852
- nodes.forEach((node) => {
853
- if (node.nodeType !== Node.ELEMENT_NODE) {
854
- return
855
- }
856
- const typed = node as Element
857
- const name = typed.localName
858
- if (name === 'viz-association') {
859
- this[processAddedAssociation](typed as VizAssociationElement)
860
- } else {
861
- this[processAddedNode](typed as HTMLElement)
862
- }
863
- const children = typed.querySelectorAll('*')
864
- this[processAddedNodes](children)
865
- })
866
- }
867
-
868
- /**
869
- * Processes removed from the canvas elements.
870
- * @param nodes The list of removed nodes
871
- */
872
- [processRemovedNodes](nodes: NodeList): void {
873
- nodes.forEach((node) => {
874
- if (node.nodeType !== Node.ELEMENT_NODE) {
875
- return
876
- }
877
- const typed = node as Element
878
- const name = typed.localName
879
- if (name === 'viz-association') {
880
- this[processRemovedAssociation](typed as VizAssociationElement)
881
- } else {
882
- this[processRemovedNode](typed as HTMLElement)
883
- }
884
- const children = typed.querySelectorAll('*')
885
- this[processRemovedNodes](children)
886
- })
887
- this.syncAssociations()
888
- }
889
-
890
- /**
891
- * Processes changed attribute on any element in the canvas
892
- * @param mutation The record associated with the change
893
- */
894
- [processAttributeChanged](mutation: MutationRecord): void {
895
- const att = mutation.attributeName as string
896
- // console.log(att);
897
-
898
- const nodeName = mutation.target.nodeName.toLowerCase()
899
- const isAssociation = nodeName === 'viz-association'
900
-
901
- if (att === 'data-key') {
902
- if (isAssociation) {
903
- const typed = mutation.target as VizAssociationElement
904
- const old = mutation.oldValue
905
- const id = typed.dataset.id
906
- if (old && id && this[edgesValue].has(old)) {
907
- const value = this[edgesValue].get(old) as IWorkspaceEdge
908
- this[edgesValue].delete(old)
909
- this[edgesValue].set(id, value)
910
- } else if (old && this[edgesValue].has(old)) {
911
- this.removeEdge(old)
912
- }
913
- } else {
914
- const typed = mutation.target as HTMLElement
915
- this[processAddedNode](typed)
916
- }
917
- } else if (isAssociation) {
918
- const typed = mutation.target as VizAssociationElement
919
- if (att === 'target') {
920
- this[processAddedAssociation](typed)
921
- } else if (['name', 'displayName'].includes(att)) {
922
- this.updateAssociationLabel(typed)
923
- } else if (att === 'selected') {
924
- this.toggleEdgeHighlight(typed)
925
- } else if (att === 'secondary-selected') {
926
- this.toggleEdgeSecondaryHighlight(typed)
927
- } else if (att === 'data-marker-end') {
928
- this.updateEdgeMarker(typed)
929
- } else if (att === 'data-style') {
930
- this.updateEdgeStyles(typed)
931
- }
932
- }
933
- }
934
-
935
- /**
936
- * If the target exists it creates the model of the association
937
- * and adds it to the associations list.
938
- * If the target is not set the association is ignored.
939
- * If the parent has no `data-key` it is ignored.
940
- * If the target does not exists it is ignored (handled in processAddedNode)
941
- */
942
- [processAddedAssociation](node: VizAssociationElement): void {
943
- const { target, key } = node.dataset
944
- if (!target) {
945
- if (key) {
946
- this.removeEdge(key)
947
- }
948
- return
949
- }
950
- const targetElement = this.findDomainTarget(target)
951
- if (!targetElement) {
952
- if (key) {
953
- this.removeEdge(key)
954
- }
955
- return
956
- }
957
- this.queueAssociation(node)
958
- }
959
-
960
- /**
961
- * If there is an association that corresponds to the `data-key` of the element
962
- * then it builds the association model.
963
- */
964
- [processAddedNode](node: HTMLElement): void {
965
- const { key } = node.dataset
966
- if (!key) {
967
- return
968
- }
969
- // first add associations that this node has
970
- const nodesAssociations = node.querySelectorAll('viz-association')
971
- Array.from(nodesAssociations).forEach((assocNode) => {
972
- const typed = assocNode as VizAssociationElement
973
- if (!typed.dataset.target) {
974
- return
975
- }
976
- const targetElement = this.findDomainTarget(typed.dataset.target)
977
- if (!targetElement) {
978
- return
979
- }
980
- // this.buildAssociationEdge(typed, targetElement);
981
- this.queueAssociation(typed)
982
- })
983
-
984
- // then find association to this node.
985
- const assocElement = this.workspace.querySelector(`viz-association[data-target="${key}"]`) as VizAssociationElement
986
- if (!assocElement) {
987
- return
988
- }
989
- // this.buildAssociationEdge(assocElement, node);
990
- this.queueAssociation(assocElement)
991
- }
992
-
993
- /**
994
- * If the association model exists for this association then it is removed.
995
- */
996
- [processRemovedAssociation](node: VizAssociationElement): void {
997
- const { key } = node.dataset
998
- if (key) {
999
- this.delete(key)
1000
- }
1001
- }
1002
-
1003
- /**
1004
- * If the element has an association then this association is removed.
1005
- */
1006
- [processRemovedNode](node: HTMLElement): void {
1007
- // first remove associations that this node has
1008
- const nodesAssociations = node.querySelectorAll('viz-association')
1009
- Array.from(nodesAssociations).forEach((assocNode) => {
1010
- const typed = assocNode as VizAssociationElement
1011
- if (typed.dataset.key) {
1012
- this.delete(typed.dataset.key)
1013
- }
1014
- })
1015
- // them remove association that this node is connected to
1016
- const { key } = node.dataset
1017
- if (!key) {
1018
- return
1019
- }
1020
- const assocElement = this.workspace.querySelector(`viz-association[data-target="${key}"]`) as VizAssociationElement
1021
- if (!assocElement || !assocElement.dataset.key) {
1022
- return
1023
- }
1024
- this.delete(assocElement.dataset.key)
1025
- }
1026
-
1027
- /**
1028
- * Handles selection of an association from the SVG element click.
1029
- */
1030
- [clickHandler](e: PointerEvent): void {
1031
- const typeTarget = this[readEventTarget](e)
1032
- if (!typeTarget) {
1033
- this[deselectAllEdges]()
1034
- return
1035
- }
1036
- const { type, id } = typeTarget.dataset
1037
- if (type === 'association' && id) {
1038
- this[associationClickHandler](id, e.shiftKey)
1039
- }
1040
- }
1041
-
1042
- /**
1043
- * Handles mouse over event on the SVG element
1044
- */
1045
- [mouseOverHandler](e: Event): void {
1046
- const typeTarget = this[readEventTarget](e)
1047
- if (!typeTarget) {
1048
- return
1049
- }
1050
- if (!typeTarget.classList.contains('association-line-area')) {
1051
- return
1052
- }
1053
- const { id } = typeTarget.dataset
1054
- if (!id) {
1055
- return
1056
- }
1057
- const item = this.get(id)
1058
- if (!item) {
1059
- return
1060
- }
1061
- if (item.shape.selection) {
1062
- item.shape.selection.hover = true
1063
- this.workspace.requestUpdate()
1064
- }
1065
- }
1066
-
1067
- /**
1068
- * Handles mouse out event on the SVG element
1069
- */
1070
- [mouseOutHandler](e: Event): void {
1071
- const typeTarget = this[readEventTarget](e)
1072
- if (!typeTarget) {
1073
- return
1074
- }
1075
- if (!typeTarget.classList.contains('association-line-area')) {
1076
- return
1077
- }
1078
- const { id } = typeTarget.dataset
1079
- if (!id) {
1080
- return
1081
- }
1082
- const item = this.get(id)
1083
- if (!item) {
1084
- return
1085
- }
1086
- if (item.shape.selection) {
1087
- item.shape.selection.hover = false
1088
- this.workspace.requestUpdate()
1089
- }
1090
- }
1091
-
1092
- [readEventTarget](e: Event): SVGElement | undefined {
1093
- let typeTarget: SVGElement | undefined
1094
- const path = e.composedPath()
1095
- while (path.length) {
1096
- const item = path.shift() as SVGElement
1097
- if (item.localName === 'svg') {
1098
- break
1099
- }
1100
- if (item.dataset.type && item.dataset.id) {
1101
- typeTarget = item
1102
- break
1103
- }
1104
- }
1105
- return typeTarget
1106
- }
1107
-
1108
- /**
1109
- * Handles the logic when an association visualization was clicked.
1110
- * @param id Association id
1111
- * @param multi Whether multi selection is applied
1112
- */
1113
- [associationClickHandler](id: string, multi = false): void {
1114
- const selectableTarget = this.findDomainTarget(id)
1115
- if (!selectableTarget) {
1116
- return
1117
- }
1118
- const manager = this.workspace.selection
1119
- const isSelected = manager.isSelected(selectableTarget)
1120
- if (isSelected) {
1121
- if (multi) {
1122
- manager.setUnselected(selectableTarget)
1123
- }
1124
- return
1125
- }
1126
- if (!multi) {
1127
- this[deselectAllEdges]()
1128
- manager.deselectAll()
1129
- }
1130
- manager.setSelected(selectableTarget)
1131
- }
1132
-
1133
- /**
1134
- * Removes selection from all associations
1135
- */
1136
- [deselectAllEdges](): void {
1137
- const nodes = this.workspace.querySelectorAll(`viz-association[data-selected]`)
1138
- const manager = this.workspace.selection
1139
- Array.from(nodes).forEach((node) => {
1140
- manager.setUnselected(node)
1141
- })
1142
- const map = this[edgesValue]
1143
- map.forEach((model) => {
1144
- if (!model.shape.selection) {
1145
- model.shape.selection = {}
1146
- }
1147
- model.shape.selection.primary = false
1148
- model.shape.selection.secondary = false
1149
- model.shape.selection.hover = false
1150
- })
1151
- this.workspace.requestUpdate()
1152
- }
1153
- }