@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.
- package/package.json +7 -2
- package/test/env.ts +15 -0
- package/test/tsconfig.json +1 -7
- package/web-test-runner.config.js +5 -1
- package/build/src/visualization/elements/VizAssociationElement.d.ts +0 -4
- package/build/src/visualization/elements/VizAssociationElement.d.ts.map +0 -1
- package/build/src/visualization/elements/VizAssociationElement.js +0 -4
- package/build/src/visualization/elements/VizAssociationElement.js.map +0 -1
- package/build/src/visualization/elements/VizWorkspaceElement.d.ts +0 -110
- package/build/src/visualization/elements/VizWorkspaceElement.d.ts.map +0 -1
- package/build/src/visualization/elements/VizWorkspaceElement.js +0 -321
- package/build/src/visualization/elements/VizWorkspaceElement.js.map +0 -1
- package/build/src/visualization/elements/WorkspaceStyles.d.ts +0 -3
- package/build/src/visualization/elements/WorkspaceStyles.d.ts.map +0 -1
- package/build/src/visualization/elements/WorkspaceStyles.js +0 -168
- package/build/src/visualization/elements/WorkspaceStyles.js.map +0 -1
- package/build/src/visualization/lib/AnchorFinder.d.ts +0 -64
- package/build/src/visualization/lib/AnchorFinder.d.ts.map +0 -1
- package/build/src/visualization/lib/AnchorFinder.js +0 -107
- package/build/src/visualization/lib/AnchorFinder.js.map +0 -1
- package/build/src/visualization/lib/AnchorUtils.d.ts +0 -10
- package/build/src/visualization/lib/AnchorUtils.d.ts.map +0 -1
- package/build/src/visualization/lib/AnchorUtils.js +0 -44
- package/build/src/visualization/lib/AnchorUtils.js.map +0 -1
- package/build/src/visualization/lib/AssociationAnchors.d.ts +0 -134
- package/build/src/visualization/lib/AssociationAnchors.d.ts.map +0 -1
- package/build/src/visualization/lib/AssociationAnchors.js +0 -351
- package/build/src/visualization/lib/AssociationAnchors.js.map +0 -1
- package/build/src/visualization/lib/LabelSketch.d.ts +0 -16
- package/build/src/visualization/lib/LabelSketch.d.ts.map +0 -1
- package/build/src/visualization/lib/LabelSketch.js +0 -53
- package/build/src/visualization/lib/LabelSketch.js.map +0 -1
- package/build/src/visualization/lib/LineSketch.d.ts +0 -26
- package/build/src/visualization/lib/LineSketch.d.ts.map +0 -1
- package/build/src/visualization/lib/LineSketch.js +0 -55
- package/build/src/visualization/lib/LineSketch.js.map +0 -1
- package/build/src/visualization/lib/Point.d.ts +0 -74
- package/build/src/visualization/lib/Point.d.ts.map +0 -1
- package/build/src/visualization/lib/Point.js +0 -121
- package/build/src/visualization/lib/Point.js.map +0 -1
- package/build/src/visualization/lib/PositionUtils.d.ts +0 -65
- package/build/src/visualization/lib/PositionUtils.d.ts.map +0 -1
- package/build/src/visualization/lib/PositionUtils.js +0 -205
- package/build/src/visualization/lib/PositionUtils.js.map +0 -1
- package/build/src/visualization/lib/SelectionManager.d.ts +0 -183
- package/build/src/visualization/lib/SelectionManager.d.ts.map +0 -1
- package/build/src/visualization/lib/SelectionManager.js +0 -481
- package/build/src/visualization/lib/SelectionManager.js.map +0 -1
- package/build/src/visualization/lib/ShapeArtist.d.ts +0 -45
- package/build/src/visualization/lib/ShapeArtist.d.ts.map +0 -1
- package/build/src/visualization/lib/ShapeArtist.js +0 -209
- package/build/src/visualization/lib/ShapeArtist.js.map +0 -1
- package/build/src/visualization/lib/SvgMarkers.d.ts +0 -14
- package/build/src/visualization/lib/SvgMarkers.d.ts.map +0 -1
- package/build/src/visualization/lib/SvgMarkers.js +0 -77
- package/build/src/visualization/lib/SvgMarkers.js.map +0 -1
- package/build/src/visualization/lib/TipSketch.d.ts +0 -26
- package/build/src/visualization/lib/TipSketch.d.ts.map +0 -1
- package/build/src/visualization/lib/TipSketch.js +0 -77
- package/build/src/visualization/lib/TipSketch.js.map +0 -1
- package/build/src/visualization/lib/TouchSupport.d.ts +0 -14
- package/build/src/visualization/lib/TouchSupport.d.ts.map +0 -1
- package/build/src/visualization/lib/TouchSupport.js +0 -55
- package/build/src/visualization/lib/TouchSupport.js.map +0 -1
- package/build/src/visualization/lib/Utils.d.ts +0 -25
- package/build/src/visualization/lib/Utils.d.ts.map +0 -1
- package/build/src/visualization/lib/Utils.js +0 -59
- package/build/src/visualization/lib/Utils.js.map +0 -1
- package/build/src/visualization/lib/VisualizationTypes.d.ts +0 -216
- package/build/src/visualization/lib/VisualizationTypes.d.ts.map +0 -1
- package/build/src/visualization/lib/VisualizationTypes.js +0 -3
- package/build/src/visualization/lib/VisualizationTypes.js.map +0 -1
- package/build/src/visualization/lib/WorkspaceAlignment.d.ts +0 -51
- package/build/src/visualization/lib/WorkspaceAlignment.d.ts.map +0 -1
- package/build/src/visualization/lib/WorkspaceAlignment.js +0 -243
- package/build/src/visualization/lib/WorkspaceAlignment.js.map +0 -1
- package/build/src/visualization/lib/WorkspaceDebugging.d.ts +0 -104
- package/build/src/visualization/lib/WorkspaceDebugging.d.ts.map +0 -1
- package/build/src/visualization/lib/WorkspaceDebugging.js +0 -286
- package/build/src/visualization/lib/WorkspaceDebugging.js.map +0 -1
- package/build/src/visualization/lib/WorkspaceEdges.d.ts +0 -293
- package/build/src/visualization/lib/WorkspaceEdges.d.ts.map +0 -1
- package/build/src/visualization/lib/WorkspaceEdges.js +0 -1073
- package/build/src/visualization/lib/WorkspaceEdges.js.map +0 -1
- package/build/src/visualization/lib/WorkspaceGestures.d.ts +0 -119
- package/build/src/visualization/lib/WorkspaceGestures.d.ts.map +0 -1
- package/build/src/visualization/lib/WorkspaceGestures.js +0 -376
- package/build/src/visualization/lib/WorkspaceGestures.js.map +0 -1
- package/build/src/visualization/lib/WorkspaceSizing.d.ts +0 -66
- package/build/src/visualization/lib/WorkspaceSizing.d.ts.map +0 -1
- package/build/src/visualization/lib/WorkspaceSizing.js +0 -168
- package/build/src/visualization/lib/WorkspaceSizing.js.map +0 -1
- package/build/src/visualization/lib/lines/RectilinearLine.d.ts +0 -114
- package/build/src/visualization/lib/lines/RectilinearLine.d.ts.map +0 -1
- package/build/src/visualization/lib/lines/RectilinearLine.js +0 -605
- package/build/src/visualization/lib/lines/RectilinearLine.js.map +0 -1
- package/build/src/visualization/lib/tips/RectilinearTip.d.ts +0 -26
- package/build/src/visualization/lib/tips/RectilinearTip.d.ts.map +0 -1
- package/build/src/visualization/lib/tips/RectilinearTip.js +0 -149
- package/build/src/visualization/lib/tips/RectilinearTip.js.map +0 -1
- package/build/src/visualization/lib/tips/TipArtist.d.ts +0 -22
- package/build/src/visualization/lib/tips/TipArtist.d.ts.map +0 -1
- package/build/src/visualization/lib/tips/TipArtist.js +0 -31
- package/build/src/visualization/lib/tips/TipArtist.js.map +0 -1
- package/build/src/visualization/lib/types.d.ts +0 -164
- package/build/src/visualization/lib/types.d.ts.map +0 -1
- package/build/src/visualization/lib/types.js +0 -2
- package/build/src/visualization/lib/types.js.map +0 -1
- package/build/src/visualization/plugin/dnd/DragAndDropPlugin.d.ts +0 -126
- package/build/src/visualization/plugin/dnd/DragAndDropPlugin.d.ts.map +0 -1
- package/build/src/visualization/plugin/dnd/DragAndDropPlugin.js +0 -260
- package/build/src/visualization/plugin/dnd/DragAndDropPlugin.js.map +0 -1
- package/build/src/visualization/plugin/group-selection/GroupSelection.d.ts +0 -93
- package/build/src/visualization/plugin/group-selection/GroupSelection.d.ts.map +0 -1
- package/build/src/visualization/plugin/group-selection/GroupSelection.js +0 -250
- package/build/src/visualization/plugin/group-selection/GroupSelection.js.map +0 -1
- package/build/src/visualization/plugin/positioning/DataModelLayout.d.ts +0 -10
- package/build/src/visualization/plugin/positioning/DataModelLayout.d.ts.map +0 -1
- package/build/src/visualization/plugin/positioning/DataModelLayout.js +0 -105
- package/build/src/visualization/plugin/positioning/DataModelLayout.js.map +0 -1
- package/build/src/visualization/plugin/positioning/WorkspaceLayout.d.ts +0 -93
- package/build/src/visualization/plugin/positioning/WorkspaceLayout.d.ts.map +0 -1
- package/build/src/visualization/plugin/positioning/WorkspaceLayout.js +0 -96
- package/build/src/visualization/plugin/positioning/WorkspaceLayout.js.map +0 -1
- package/build/src/visualization/viz-association.d.ts +0 -7
- package/build/src/visualization/viz-association.d.ts.map +0 -1
- package/build/src/visualization/viz-association.js +0 -3
- package/build/src/visualization/viz-association.js.map +0 -1
- package/build/src/visualization/viz-workspace.d.ts +0 -7
- package/build/src/visualization/viz-workspace.d.ts.map +0 -1
- package/build/src/visualization/viz-workspace.js +0 -3
- package/build/src/visualization/viz-workspace.js.map +0 -1
- package/src/visualization/elements/VizAssociationElement.ts +0 -3
- package/src/visualization/elements/VizWorkspaceElement.ts +0 -302
- package/src/visualization/elements/WorkspaceStyles.ts +0 -168
- package/src/visualization/lib/AnchorFinder.ts +0 -112
- package/src/visualization/lib/AnchorUtils.ts +0 -53
- package/src/visualization/lib/AssociationAnchors.ts +0 -418
- package/src/visualization/lib/LabelSketch.ts +0 -67
- package/src/visualization/lib/LineSketch.ts +0 -62
- package/src/visualization/lib/Point.ts +0 -134
- package/src/visualization/lib/PositionUtils.ts +0 -218
- package/src/visualization/lib/SelectionManager.ts +0 -513
- package/src/visualization/lib/ShapeArtist.ts +0 -222
- package/src/visualization/lib/SvgMarkers.ts +0 -80
- package/src/visualization/lib/TipSketch.ts +0 -91
- package/src/visualization/lib/TouchSupport.ts +0 -72
- package/src/visualization/lib/Utils.ts +0 -63
- package/src/visualization/lib/VisualizationTypes.ts +0 -232
- package/src/visualization/lib/WorkspaceAlignment.ts +0 -261
- package/src/visualization/lib/WorkspaceDebugging.ts +0 -313
- package/src/visualization/lib/WorkspaceEdges.ts +0 -1153
- package/src/visualization/lib/WorkspaceGestures.ts +0 -400
- package/src/visualization/lib/WorkspaceSizing.ts +0 -181
- package/src/visualization/lib/lines/RectilinearLine.ts +0 -589
- package/src/visualization/lib/tips/RectilinearTip.ts +0 -156
- package/src/visualization/lib/tips/TipArtist.ts +0 -34
- package/src/visualization/lib/types.ts +0 -173
- package/src/visualization/plugin/dnd/DragAndDropPlugin.ts +0 -294
- package/src/visualization/plugin/group-selection/GroupSelection.ts +0 -271
- package/src/visualization/plugin/positioning/DataModelLayout.ts +0 -114
- package/src/visualization/plugin/positioning/WorkspaceLayout.ts +0 -149
- package/src/visualization/viz-association.ts +0 -9
- package/src/visualization/viz-workspace.ts +0 -9
- package/test/env.d.ts +0 -9
- package/test/env.js +0 -7
- package/test/visualization/lib/AnchorFinder.test.ts +0 -313
- package/test/visualization/lib/AnchorUtils.test.ts +0 -178
- package/test/visualization/lib/PositionUtils.test.ts +0 -406
- 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
|
-
}
|