@processmaker/modeler 1.24.4 → 1.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/modeler.common.js +2019 -599
- package/dist/modeler.common.js.map +1 -1
- package/dist/modeler.umd.js +2019 -599
- package/dist/modeler.umd.js.map +1 -1
- package/dist/modeler.umd.min.js +3 -3
- package/dist/modeler.umd.min.js.map +1 -1
- package/package.json +1 -1
- package/src/.DS_Store +0 -0
- package/src/components/controls/controls.scss +8 -3
- package/src/components/crown/crownConfig/crownConfig.scss +1 -1
- package/src/components/crown/crownConfig/crownConfig.vue +5 -1
- package/src/components/crown/crownMultiselect/crownMultiselect.vue +140 -0
- package/src/components/hotkeys/main.js +62 -0
- package/src/components/hotkeys/zoomInOut.js +29 -0
- package/src/components/inspectors/InspectorPanel.vue +1 -0
- package/src/components/inspectors/inspector.scss +1 -1
- package/src/components/modeler/Modeler.vue +189 -46
- package/src/components/modeler/Selection.vue +705 -0
- package/src/components/modeler/modeler.scss +0 -1
- package/src/components/nodes/boundaryEvent/boundaryEvent.vue +3 -0
- package/src/components/nodes/pool/poolEventHandlers.js +1 -0
- package/src/components/paperManager.js +2 -0
- package/src/components/toolbar/ToolBar.vue +95 -22
- package/src/components/toolbar/toolbar.scss +18 -2
- package/src/mixins/highlightConfig.js +2 -0
- package/src/mixins/linkConfig.js +3 -0
- package/src/store.js +12 -1
- package/src/undoRedoStore.js +45 -0
- /package/src/components/{modeler → hotkeys}/moveWithArrowKeys.js +0 -0
|
@@ -0,0 +1,705 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
ref="drag"
|
|
4
|
+
v-if="showLasso && style"
|
|
5
|
+
class="box"
|
|
6
|
+
data-cy="selection-box"
|
|
7
|
+
:data-length="selected.length"
|
|
8
|
+
:style="style"
|
|
9
|
+
>
|
|
10
|
+
<crown-multiselect
|
|
11
|
+
:paper="paperManager.paper"
|
|
12
|
+
:graph="$parent.graph"
|
|
13
|
+
:moddle="$parent.moddle"
|
|
14
|
+
:collaboration="$parent.collaboration"
|
|
15
|
+
:process-node="$parent.processNode"
|
|
16
|
+
:plane-elements="$parent.planeElements"
|
|
17
|
+
:is-rendering="$parent.isRendering"
|
|
18
|
+
:dropdown-data="[]"
|
|
19
|
+
v-on="$listeners"
|
|
20
|
+
/>
|
|
21
|
+
</div>
|
|
22
|
+
</template>
|
|
23
|
+
|
|
24
|
+
<script>
|
|
25
|
+
import { util, g, V } from 'jointjs';
|
|
26
|
+
import store from '@/store';
|
|
27
|
+
import CrownMultiselect from '@/components/crown/crownMultiselect/crownMultiselect';
|
|
28
|
+
import { id as poolId } from '@/components/nodes/pool/config';
|
|
29
|
+
import { id as laneId } from '@/components/nodes/poolLane/config';
|
|
30
|
+
import { id as genericFlowId } from '@/components/nodes/genericFlow/config';
|
|
31
|
+
import { labelWidth, poolPadding } from '../nodes/pool/poolSizes';
|
|
32
|
+
export default {
|
|
33
|
+
name: 'Selection',
|
|
34
|
+
components: {
|
|
35
|
+
CrownMultiselect,
|
|
36
|
+
},
|
|
37
|
+
props: {
|
|
38
|
+
graph: Object,
|
|
39
|
+
paperManager: Object,
|
|
40
|
+
useModelGeometry: Boolean,
|
|
41
|
+
processNode: Object,
|
|
42
|
+
},
|
|
43
|
+
data() {
|
|
44
|
+
return {
|
|
45
|
+
start: null,
|
|
46
|
+
isSelecting: false,
|
|
47
|
+
isSelected: false,
|
|
48
|
+
selected: [],
|
|
49
|
+
dragging: false,
|
|
50
|
+
style: {
|
|
51
|
+
left: '0px',
|
|
52
|
+
top: '0px',
|
|
53
|
+
width: '0px',
|
|
54
|
+
height: '0px',
|
|
55
|
+
},
|
|
56
|
+
mouseX: 0,
|
|
57
|
+
mouseY: 0,
|
|
58
|
+
top: 0,
|
|
59
|
+
left: 0,
|
|
60
|
+
initialPosition: null,
|
|
61
|
+
hasMouseDown: false,
|
|
62
|
+
hasMouseMoved: false,
|
|
63
|
+
showLasso: false,
|
|
64
|
+
isOutOfThePool: false,
|
|
65
|
+
stopForceMove: false,
|
|
66
|
+
draggableBlackList: [
|
|
67
|
+
laneId,
|
|
68
|
+
],
|
|
69
|
+
selectionBlackList:[
|
|
70
|
+
genericFlowId,
|
|
71
|
+
],
|
|
72
|
+
selectableBlackList:[
|
|
73
|
+
genericFlowId,
|
|
74
|
+
],
|
|
75
|
+
};
|
|
76
|
+
},
|
|
77
|
+
mounted(){
|
|
78
|
+
this.paperManager.paper.on('scale:changed ', this.updateSelectionBox);
|
|
79
|
+
this.paperManager.paper.on('translate:changed ', this.translateChanged);
|
|
80
|
+
},
|
|
81
|
+
watch: {
|
|
82
|
+
// whenever selected changes
|
|
83
|
+
selected(newSelected) {
|
|
84
|
+
this.addToHighlightedNodes(newSelected);
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
methods: {
|
|
88
|
+
/**
|
|
89
|
+
* Select an element dinamically.
|
|
90
|
+
* Shift key will manage the condition to push to selection
|
|
91
|
+
* @param {Object} view
|
|
92
|
+
* @param {Boolean} shiftKey
|
|
93
|
+
*/
|
|
94
|
+
async selectElement(view, shiftKey = false) {
|
|
95
|
+
if (view.model.component && this.selectableBlackList.includes(view.model.component.node.type)) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
this.showLasso = true;
|
|
99
|
+
this.isSelected = true;
|
|
100
|
+
this.isSelecting = true;
|
|
101
|
+
this.start = null;
|
|
102
|
+
if (shiftKey) {
|
|
103
|
+
this.shiftKeySelectionHandler(view);
|
|
104
|
+
} else {
|
|
105
|
+
this.selected = [view];
|
|
106
|
+
}
|
|
107
|
+
this.filterSelected();
|
|
108
|
+
await this.$nextTick();
|
|
109
|
+
this.updateSelectionBox();
|
|
110
|
+
},
|
|
111
|
+
/**
|
|
112
|
+
* Select or unselect an element with shift key pressed
|
|
113
|
+
* @param {Object} view
|
|
114
|
+
*/
|
|
115
|
+
shiftKeySelectionHandler(view){
|
|
116
|
+
// validate if current shape is black listed
|
|
117
|
+
if (view && view.model && view.model.component &&
|
|
118
|
+
this.draggableBlackList.includes(view.model.component.node.type)) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
// validate if there is a lane previously selected
|
|
122
|
+
let lane = this.selected.find(view => {
|
|
123
|
+
return this.draggableBlackList.includes(view.model.component.node.type);
|
|
124
|
+
});
|
|
125
|
+
if (lane) {
|
|
126
|
+
this.selected = [view];
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
// validate if the current selection is a pool
|
|
130
|
+
if (view.model.component && view.model.component.node.type === poolId) {
|
|
131
|
+
//validate if previous selection are all pools
|
|
132
|
+
if (this.hasOnlyPools(this.selected)) {
|
|
133
|
+
this.selectOrUnselectShape(view);
|
|
134
|
+
} else {
|
|
135
|
+
this.selected = [view];
|
|
136
|
+
}
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
this.selectOrUnselectShape(view);
|
|
140
|
+
},
|
|
141
|
+
/**
|
|
142
|
+
* Select an shape if it is not in the collection
|
|
143
|
+
* Unselect an shape if it is in the collection
|
|
144
|
+
*/
|
|
145
|
+
selectOrUnselectShape(view){
|
|
146
|
+
const element = this.selected.find( item => item.id === view.id);
|
|
147
|
+
if (element) {
|
|
148
|
+
this.selected = this.selected.filter(item => item.id !== view.id);
|
|
149
|
+
} else {
|
|
150
|
+
this.selected.push(view);
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
clearSelection() {
|
|
154
|
+
this.initSelection();
|
|
155
|
+
},
|
|
156
|
+
initSelection(){
|
|
157
|
+
this.isSelecting = false;
|
|
158
|
+
this.start = null;
|
|
159
|
+
this.selected = [];
|
|
160
|
+
this.showLasso = false;
|
|
161
|
+
this.isSelected = false;
|
|
162
|
+
this.style = {
|
|
163
|
+
left: '0px',
|
|
164
|
+
top: '0px',
|
|
165
|
+
width: '0px',
|
|
166
|
+
height: '0px',
|
|
167
|
+
};
|
|
168
|
+
},
|
|
169
|
+
/**
|
|
170
|
+
* Starts the selection box
|
|
171
|
+
* @param {Object} event
|
|
172
|
+
*/
|
|
173
|
+
startSelection(event) {
|
|
174
|
+
const { paper } = this.paperManager;
|
|
175
|
+
const { clientX, clientY, offsetX, offsetY } = util.normalizeEvent(event);
|
|
176
|
+
const paperOffset = paper.$el.offset();
|
|
177
|
+
this.clearSelection();
|
|
178
|
+
this.isSelecting = true;
|
|
179
|
+
this.showLasso = true;
|
|
180
|
+
this.start = {
|
|
181
|
+
x: clientX - paperOffset.left + window.pageXOffset + paper.$el.scrollLeft(),
|
|
182
|
+
y: clientY - paperOffset.top + window.pageYOffset + paper.$el.scrollTop(),
|
|
183
|
+
};
|
|
184
|
+
this._offset = { x: offsetX, y: offsetY };
|
|
185
|
+
},
|
|
186
|
+
/**
|
|
187
|
+
* Updates the selection box
|
|
188
|
+
* @param {Object} event
|
|
189
|
+
*/
|
|
190
|
+
updateSelection(event) {
|
|
191
|
+
const { paper } = this.paperManager;
|
|
192
|
+
if (this.isSelecting && !this.isSelected && this.start) {
|
|
193
|
+
const nEvent= util.normalizeEvent(event);
|
|
194
|
+
const paperOffset = paper.$el.offset();
|
|
195
|
+
const end = {
|
|
196
|
+
x: nEvent.clientX - paperOffset.left + window.pageXOffset + paper.$el.scrollLeft(),
|
|
197
|
+
y: nEvent.clientY - paperOffset.top + window.pageYOffset + paper.$el.scrollTop(),
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
const size = {
|
|
201
|
+
height: end.y - this.start.y,
|
|
202
|
+
width: end.x - this.start.x,
|
|
203
|
+
};
|
|
204
|
+
// Set the position of the element
|
|
205
|
+
this.style.left =`${size.width < 0 ? this._offset.x + size.width: this.start.x}px`;
|
|
206
|
+
this.style.top = `${size.height < 0 ? this._offset.y + size.height: this.start.y}px`;
|
|
207
|
+
// Set the dimensions of the element
|
|
208
|
+
this.style.width = `${Math.abs(size.width)}px`;
|
|
209
|
+
this.style.height = `${Math.abs(size.height)}px`;
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
/**
|
|
213
|
+
* End the selection box
|
|
214
|
+
*/
|
|
215
|
+
endSelection() {
|
|
216
|
+
const { paper } = this.paperManager;
|
|
217
|
+
if (!this.isSelecting || this.isSelected) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
const paperOffset = paper.$el.offset();
|
|
221
|
+
|
|
222
|
+
const selectorOffset = {
|
|
223
|
+
left: this.$el.offsetLeft + paperOffset.left,
|
|
224
|
+
top: this.$el.offsetTop + paperOffset.top,
|
|
225
|
+
};
|
|
226
|
+
let width = this.$el.clientWidth;
|
|
227
|
+
let height = this.$el.clientHeight;
|
|
228
|
+
|
|
229
|
+
const f = V(paper.viewport).toLocalPoint(selectorOffset.left, selectorOffset.top);
|
|
230
|
+
f.x -= window.pageXOffset;
|
|
231
|
+
f.y -= window.pageYOffset;
|
|
232
|
+
const scale = paper.scale();
|
|
233
|
+
width /= scale.sx;
|
|
234
|
+
height /= scale.sy;
|
|
235
|
+
|
|
236
|
+
let selectedArea = g.rect(f.x, f.y, width, height);
|
|
237
|
+
this.selected = this.getElementsInSelectedArea(selectedArea, { strict: false });
|
|
238
|
+
this.filterSelected();
|
|
239
|
+
if (this.selected && this.selected.length > 0) {
|
|
240
|
+
this.updateSelectionBox();
|
|
241
|
+
this.isSelected = true;
|
|
242
|
+
} else {
|
|
243
|
+
this.clearSelection();
|
|
244
|
+
this.isSelected = false;
|
|
245
|
+
this.start = null;
|
|
246
|
+
}
|
|
247
|
+
this.start = null;
|
|
248
|
+
},
|
|
249
|
+
/**
|
|
250
|
+
* Get elements into a selected area
|
|
251
|
+
* @param {Object} area
|
|
252
|
+
*/
|
|
253
|
+
getElementsInSelectedArea(area, options, addLinks=true) {
|
|
254
|
+
const { paper } = this.paperManager;
|
|
255
|
+
const elements = paper.findViewsInArea(area, options);
|
|
256
|
+
|
|
257
|
+
if (!addLinks) {
|
|
258
|
+
return elements;
|
|
259
|
+
}
|
|
260
|
+
// get flows
|
|
261
|
+
this.graph.getLinks().forEach(function(link) {
|
|
262
|
+
// Check if the link is within the selected area
|
|
263
|
+
if (area.intersect(link.getBBox())) {
|
|
264
|
+
// The link is within the selected area
|
|
265
|
+
// Do something with the link, such as highlighting it
|
|
266
|
+
elements.push(paper.findViewByModel(link));
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
return elements;
|
|
270
|
+
},
|
|
271
|
+
/**
|
|
272
|
+
* Return the bounding box of the selected elements,
|
|
273
|
+
* @param {Array} selected
|
|
274
|
+
*/
|
|
275
|
+
getSelectionVertex(selected, byModel = false, includeAll = false) {
|
|
276
|
+
const point = { x : 1 / 0, y: 1 / 0 };
|
|
277
|
+
const size = { width: 0, height: 0 };
|
|
278
|
+
const useModelGeometry = this.useModelGeometry;
|
|
279
|
+
const shapesToNotTranslate = [
|
|
280
|
+
'PoolLane',
|
|
281
|
+
'standard.Link',
|
|
282
|
+
];
|
|
283
|
+
selected.filter(shape => includeAll || !shapesToNotTranslate.includes(shape.model.get('type')))
|
|
284
|
+
.map(function(view) {
|
|
285
|
+
const box = byModel ?
|
|
286
|
+
view.model.getBBox({ useModelGeometry }) :
|
|
287
|
+
view.getBBox({ useModelGeometry }).inflate(7);
|
|
288
|
+
point.x = Math.min(point.x, box.x);
|
|
289
|
+
point.y = Math.min(point.y, box.y);
|
|
290
|
+
size.width = Math.max(size.width, box.x + box.width);
|
|
291
|
+
size.height= Math.max(size.height, box.y + box.height);
|
|
292
|
+
});
|
|
293
|
+
return {
|
|
294
|
+
minX: point.x,
|
|
295
|
+
minY: point.y,
|
|
296
|
+
maxX: size.width,
|
|
297
|
+
maxY: size.height,
|
|
298
|
+
};
|
|
299
|
+
},
|
|
300
|
+
/**
|
|
301
|
+
* Update the selection Box
|
|
302
|
+
*/
|
|
303
|
+
updateSelectionBox(force=false) {
|
|
304
|
+
if (force || this.isSelecting && this.style) {
|
|
305
|
+
if (this.selected.length > 0) {
|
|
306
|
+
const box = this.getSelectionVertex(this.selected, false, true);
|
|
307
|
+
// Set the position of the element
|
|
308
|
+
this.style.left = `${box.minX}px`;
|
|
309
|
+
this.style.top = `${box.minY}px`;
|
|
310
|
+
this.left = parseInt(this.style.left);
|
|
311
|
+
this.top = parseInt(this.style.top);
|
|
312
|
+
// Set the dimensions of the element
|
|
313
|
+
this.style.width = `${box.maxX - box.minX}px`;
|
|
314
|
+
this.style.height = `${box.maxY - box.minY}px`;
|
|
315
|
+
} else {
|
|
316
|
+
this.clearSelection();
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
},
|
|
320
|
+
/**
|
|
321
|
+
* Filter the selected elements
|
|
322
|
+
*/
|
|
323
|
+
filterSelected() {
|
|
324
|
+
// remove from selection the selected child nodes in the pool
|
|
325
|
+
const selectedPoolsIds = this.selected
|
|
326
|
+
.filter(shape => shape.model.component)
|
|
327
|
+
.filter(shape => shape.model.component.node.type === 'processmaker-modeler-pool')
|
|
328
|
+
.map(shape => shape.model.component.node.id);
|
|
329
|
+
this.selected = this.selected.filter(shape => {
|
|
330
|
+
if (shape.model.component && shape.model.component.node.pool) {
|
|
331
|
+
return shape.model.component.node.pool && !selectedPoolsIds.includes(shape.model.component.node.pool.component.node.id);
|
|
332
|
+
}
|
|
333
|
+
return true;
|
|
334
|
+
}).filter(shape => {
|
|
335
|
+
return !(shape.model.getParentCell() && shape.model.getParentCell().get('parent'));
|
|
336
|
+
});
|
|
337
|
+
},
|
|
338
|
+
/**
|
|
339
|
+
* Pan paper handler
|
|
340
|
+
*/
|
|
341
|
+
translateChanged() {
|
|
342
|
+
if (this.isSelecting) {
|
|
343
|
+
this.updateSelectionBox();
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
/**
|
|
347
|
+
* Verify if has selected lanes
|
|
348
|
+
*/
|
|
349
|
+
hasLanes(selected) {
|
|
350
|
+
const shapesToNotTranslate = [
|
|
351
|
+
'processmaker-modeler-lane',
|
|
352
|
+
];
|
|
353
|
+
const shapes = selected.find(shape => {
|
|
354
|
+
return shapesToNotTranslate.includes(shape.model.component.node.type);
|
|
355
|
+
});
|
|
356
|
+
if (shapes) {
|
|
357
|
+
return true;
|
|
358
|
+
}
|
|
359
|
+
return false;
|
|
360
|
+
},
|
|
361
|
+
/**
|
|
362
|
+
* Verify if has only flows
|
|
363
|
+
*/
|
|
364
|
+
hasOnlyLinks(selected) {
|
|
365
|
+
let shapes = this.selected.filter(shape => {
|
|
366
|
+
return shape.model.get('type') === 'standard.Link';
|
|
367
|
+
});
|
|
368
|
+
return shapes && selected.length === shapes.length;
|
|
369
|
+
},
|
|
370
|
+
/**
|
|
371
|
+
* Verify if has selected one Pools
|
|
372
|
+
*/
|
|
373
|
+
hasOnlyPools(selected) {
|
|
374
|
+
let shapes = this.selected.filter(shape => {
|
|
375
|
+
return shape.model.component && shape.model.component.node.type === poolId;
|
|
376
|
+
});
|
|
377
|
+
return shapes && selected.length === shapes.length;
|
|
378
|
+
},
|
|
379
|
+
/**
|
|
380
|
+
* Start the drag procedure for the selext box
|
|
381
|
+
* @param {Object} event
|
|
382
|
+
*/
|
|
383
|
+
startDrag(event) {
|
|
384
|
+
if (!this.$refs.drag){
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
this.stopForceMove = false;
|
|
388
|
+
this.dragging = true;
|
|
389
|
+
this.hasMouseMoved = false;
|
|
390
|
+
const nEvent= util.normalizeEvent(event);
|
|
391
|
+
this.mouseX = nEvent.clientX;
|
|
392
|
+
this.mouseY = nEvent.clientY;
|
|
393
|
+
this.top = this.$refs.drag.offsetTop;
|
|
394
|
+
this.left = this.$refs.drag.offsetLeft;
|
|
395
|
+
this.initialPosition = {
|
|
396
|
+
top: this.top,
|
|
397
|
+
left: this.left,
|
|
398
|
+
};
|
|
399
|
+
if (this.hasLanes(this.selected)) {
|
|
400
|
+
this.stopForceMove = true;
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
if (this.hasOnlyLinks(this.selected)) {
|
|
404
|
+
this.stopForceMove = true;
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
if (this.selected && this.selected.length === 1 &&
|
|
408
|
+
this.selected[0].model.get('type') === 'processmaker.components.nodes.boundaryEvent.Shape') {
|
|
409
|
+
this.selected[0].model.component.attachToValidTarget(this.selected[0]);
|
|
410
|
+
}
|
|
411
|
+
},
|
|
412
|
+
/**
|
|
413
|
+
* on Drag procedure
|
|
414
|
+
* @param {*} event
|
|
415
|
+
*/
|
|
416
|
+
drag(event) {
|
|
417
|
+
if (this.stopForceMove) return;
|
|
418
|
+
if (!this.dragging) return;
|
|
419
|
+
this.hasMouseMoved = true;
|
|
420
|
+
const nEvent= util.normalizeEvent(event);
|
|
421
|
+
const deltaX = nEvent.clientX - this.mouseX;
|
|
422
|
+
const deltaY = nEvent.clientY - this.mouseY;
|
|
423
|
+
this.top += deltaY;
|
|
424
|
+
this.left += deltaX;
|
|
425
|
+
this.mouseX = nEvent.clientX;
|
|
426
|
+
this.mouseY = nEvent.clientY;
|
|
427
|
+
// Set the position of the element
|
|
428
|
+
const scale = this.paperManager.paper.scale();
|
|
429
|
+
this.style.left =`${this.left}px`;
|
|
430
|
+
this.style.top = `${this.top}px`;
|
|
431
|
+
this.translateSelectedShapes(deltaX/scale.sx, deltaY/scale.sy);
|
|
432
|
+
this.overPoolDrag(event);
|
|
433
|
+
},
|
|
434
|
+
/**
|
|
435
|
+
* Stop drag procedure
|
|
436
|
+
* @param {Object} event
|
|
437
|
+
*/
|
|
438
|
+
stopDrag() {
|
|
439
|
+
this.overPoolStopDrag();
|
|
440
|
+
this.$emit('save-state');
|
|
441
|
+
this.dragging = false;
|
|
442
|
+
this.stopForceMove = false;
|
|
443
|
+
},
|
|
444
|
+
/**
|
|
445
|
+
* Translate the Selected shapes adding some custom validations
|
|
446
|
+
*/
|
|
447
|
+
translateSelectedShapes(x, y, drafRef) {
|
|
448
|
+
const shapesToNotTranslate = [
|
|
449
|
+
'PoolLane',
|
|
450
|
+
'standard.Link',
|
|
451
|
+
'processmaker.components.nodes.boundaryEvent.Shape',
|
|
452
|
+
];
|
|
453
|
+
let shapes = this.selected.filter(shape => {
|
|
454
|
+
return !shapesToNotTranslate.includes(shape.model.get('type'));
|
|
455
|
+
});
|
|
456
|
+
if (drafRef) {
|
|
457
|
+
shapes.filter(shape =>{
|
|
458
|
+
return drafRef.model.get('id') !== shape.model.get('id');
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
// allow movement only if one lane boundary event is selected;
|
|
462
|
+
if (this.selected && this.selected.length === 1 &&
|
|
463
|
+
this.selected[0].model.get('type') === 'processmaker.components.nodes.boundaryEvent.Shape') {
|
|
464
|
+
this.selected[0].model.translate(x, y);
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
shapes.forEach((shape)=> shape.model.translate(x, y));
|
|
468
|
+
},
|
|
469
|
+
/**
|
|
470
|
+
* Gets shape from a point object
|
|
471
|
+
* @param {Object} event
|
|
472
|
+
*/
|
|
473
|
+
getShapesFromPoint(event){
|
|
474
|
+
const nEvent= util.normalizeEvent(event);
|
|
475
|
+
const mouseX = nEvent.clientX;
|
|
476
|
+
const mouseY = nEvent.clientY;
|
|
477
|
+
const point = V(this.paperManager.paper.viewport).toLocalPoint(mouseX, mouseY);
|
|
478
|
+
return this.paperManager.paper.findViewsFromPoint(point);
|
|
479
|
+
},
|
|
480
|
+
/**
|
|
481
|
+
* Add an element into the highlighted nodes
|
|
482
|
+
*/
|
|
483
|
+
addToHighlightedNodes(selected){
|
|
484
|
+
store.commit('highlightNode');
|
|
485
|
+
if (selected.length > 0) {
|
|
486
|
+
const selectedNodes = selected.filter(shape => shape.model.component)
|
|
487
|
+
.map(shape => shape.model.component.node);
|
|
488
|
+
store.commit('addToHighlightedNodes', selectedNodes);
|
|
489
|
+
} else {
|
|
490
|
+
store.commit('highlightNode', this.processNode);
|
|
491
|
+
}
|
|
492
|
+
},
|
|
493
|
+
/**
|
|
494
|
+
* Gets the child shape
|
|
495
|
+
* @param {object} point
|
|
496
|
+
*/
|
|
497
|
+
getChildShape(point) {
|
|
498
|
+
let result = null;
|
|
499
|
+
const views = this.getShapesFromPoint(point);
|
|
500
|
+
if (views.length === 1 ) {
|
|
501
|
+
return views[0];
|
|
502
|
+
}
|
|
503
|
+
views.forEach(shape => {
|
|
504
|
+
if (shape.model.get('parent') && shape.model.component.node.type !== laneId) {
|
|
505
|
+
result = shape;
|
|
506
|
+
}
|
|
507
|
+
});
|
|
508
|
+
return result;
|
|
509
|
+
},
|
|
510
|
+
/**
|
|
511
|
+
* Mark a shape as selected
|
|
512
|
+
* @param {object} point
|
|
513
|
+
*/
|
|
514
|
+
markSelectedByPoint(point) {
|
|
515
|
+
const element = this.getChildShape(point);
|
|
516
|
+
if (element) {
|
|
517
|
+
this.selected = [element];
|
|
518
|
+
}
|
|
519
|
+
if (this.selected.length > 0) {
|
|
520
|
+
this.isSelected = true;
|
|
521
|
+
this.isSelecting = true;
|
|
522
|
+
this.showLasso = true;
|
|
523
|
+
this.updateSelectionBox();
|
|
524
|
+
}
|
|
525
|
+
},
|
|
526
|
+
/**
|
|
527
|
+
* Get the elements that are inside the selector box
|
|
528
|
+
*/
|
|
529
|
+
getElementsInsideSelector() {
|
|
530
|
+
const { paper } = this.paperManager;
|
|
531
|
+
const paperOffset = paper.$el.offset();
|
|
532
|
+
|
|
533
|
+
const selectorOffset = {
|
|
534
|
+
left: this.$el.offsetLeft + paperOffset.left,
|
|
535
|
+
top: this.$el.offsetTop + paperOffset.top,
|
|
536
|
+
};
|
|
537
|
+
let width = this.$el.clientWidth;
|
|
538
|
+
let height = this.$el.clientHeight;
|
|
539
|
+
|
|
540
|
+
const f = V(paper.viewport).toLocalPoint(selectorOffset.left, selectorOffset.top);
|
|
541
|
+
f.x -= window.pageXOffset;
|
|
542
|
+
f.y -= window.pageYOffset;
|
|
543
|
+
const scale = paper.scale();
|
|
544
|
+
width /= scale.sx;
|
|
545
|
+
height /= scale.sy;
|
|
546
|
+
|
|
547
|
+
let selectedArea = g.rect(f.x, f.y, width, height);
|
|
548
|
+
return this.getElementsInSelectedArea(selectedArea, { strict: false });
|
|
549
|
+
},
|
|
550
|
+
/**
|
|
551
|
+
* Check that they are not in a pool
|
|
552
|
+
* @param {Array} elements
|
|
553
|
+
* @return true if there is a pool in the selection or if none of the selected elements are in a pool
|
|
554
|
+
*/
|
|
555
|
+
isNotPoolChilds(elements) {
|
|
556
|
+
if (elements.length > 0) {
|
|
557
|
+
const poolInSelection = elements.find(({ model }) => {
|
|
558
|
+
return model.component && model.component.node.type === poolId;
|
|
559
|
+
});
|
|
560
|
+
const elementInAPool = elements.find(({ model }) => {
|
|
561
|
+
return (model.getParentCell() && model.getParentCell().component.node.type === poolId);
|
|
562
|
+
});
|
|
563
|
+
return !!poolInSelection || !elementInAPool;
|
|
564
|
+
}
|
|
565
|
+
return false;
|
|
566
|
+
},
|
|
567
|
+
/**
|
|
568
|
+
* Movement controller of the elements that are inside a pool
|
|
569
|
+
*/
|
|
570
|
+
overPoolDrag(event) {
|
|
571
|
+
if (this.isNotPoolChilds(this.selected)) {
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
const elementsUnderDivArea = this.getShapesFromPoint(event);
|
|
575
|
+
const pool = elementsUnderDivArea.find(item => {
|
|
576
|
+
return item.model.component && item.model.component.node.type === poolId;
|
|
577
|
+
});
|
|
578
|
+
if (!pool) {
|
|
579
|
+
this.isOutOfThePool = true;
|
|
580
|
+
store.commit('preventSavingElementPosition');
|
|
581
|
+
this.paperManager.setStateInvalid();
|
|
582
|
+
} else {
|
|
583
|
+
this.isOutOfThePool = false;
|
|
584
|
+
store.commit('preventSavingElementPosition');
|
|
585
|
+
this.paperManager.setStateValid();
|
|
586
|
+
}
|
|
587
|
+
},
|
|
588
|
+
/**
|
|
589
|
+
* Stop dragging elements that are in a pool
|
|
590
|
+
*/
|
|
591
|
+
overPoolStopDrag(){
|
|
592
|
+
if (this.isNotPoolChilds(this.selected)) {
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
if (this.isOutOfThePool) {
|
|
596
|
+
this.rollbackSelection();
|
|
597
|
+
} else {
|
|
598
|
+
this.expandToFitElement(this.selected);
|
|
599
|
+
}
|
|
600
|
+
},
|
|
601
|
+
/**
|
|
602
|
+
* Rollback drag an element outside it's pool parent
|
|
603
|
+
*/
|
|
604
|
+
rollbackSelection(){
|
|
605
|
+
const deltaX = this.initialPosition.left - this.left;
|
|
606
|
+
const deltaY = this.initialPosition.top - this.top;
|
|
607
|
+
this.style.left = `${this.initialPosition.left}px`;
|
|
608
|
+
this.style.top = `${this.initialPosition.top}px`;
|
|
609
|
+
const scale = this.paperManager.paper.scale();
|
|
610
|
+
const shapesToNotTranslate = [
|
|
611
|
+
'PoolLane',
|
|
612
|
+
'standard.Link',
|
|
613
|
+
];
|
|
614
|
+
this.selected.filter(shape => !shapesToNotTranslate.includes(shape.model.get('type')))
|
|
615
|
+
.forEach(shape => {
|
|
616
|
+
shape.model.translate(deltaX/scale.sx, deltaY/scale.sy);
|
|
617
|
+
});
|
|
618
|
+
this.isOutOfThePool = false;
|
|
619
|
+
store.commit('allowSavingElementPosition');
|
|
620
|
+
this.paperManager.setStateValid();
|
|
621
|
+
},
|
|
622
|
+
/**
|
|
623
|
+
* Expand and fit the pool container
|
|
624
|
+
*/
|
|
625
|
+
expandToFitElement(selected) {
|
|
626
|
+
if (selected.length > 0) {
|
|
627
|
+
const pool = selected.find(({ model }) => {
|
|
628
|
+
if (model.getParentCell()) {
|
|
629
|
+
return model.getParentCell().component.node.type === poolId;
|
|
630
|
+
}
|
|
631
|
+
return false;
|
|
632
|
+
}).model.getParentCell();
|
|
633
|
+
const selectionBBox = this.getSelectionVertex(this.selected, true);
|
|
634
|
+
const { x: poolX, y: poolY, width, height } = pool.getBBox();
|
|
635
|
+
|
|
636
|
+
const elementWidth = selectionBBox.maxX - selectionBBox.minX;
|
|
637
|
+
const elementHeight = selectionBBox.maxY - selectionBBox.minY;
|
|
638
|
+
|
|
639
|
+
const relativeX = selectionBBox.minX - poolX;
|
|
640
|
+
const relativeY = selectionBBox.minY - poolY;
|
|
641
|
+
|
|
642
|
+
const rightEdge = relativeX + elementWidth;
|
|
643
|
+
const leftEdge = relativeX;
|
|
644
|
+
const topEdge = relativeY;
|
|
645
|
+
const bottomEdge = relativeY + elementHeight;
|
|
646
|
+
|
|
647
|
+
let newWidth = 0;
|
|
648
|
+
let newHeight = 0;
|
|
649
|
+
let directionHeight = 'bottom';
|
|
650
|
+
let directionWidth = 'right';
|
|
651
|
+
|
|
652
|
+
if (rightEdge > width - poolPadding) {
|
|
653
|
+
newWidth = rightEdge + poolPadding;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
if (leftEdge < labelWidth + poolPadding) {
|
|
657
|
+
newWidth = width + ((labelWidth + poolPadding) - leftEdge);
|
|
658
|
+
directionWidth = 'left';
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
if (topEdge < poolPadding) {
|
|
662
|
+
newHeight = (poolPadding - topEdge) + height;
|
|
663
|
+
directionHeight = 'top';
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
if (bottomEdge > height) {
|
|
667
|
+
newHeight = bottomEdge + poolPadding;
|
|
668
|
+
}
|
|
669
|
+
if (newWidth || newHeight) {
|
|
670
|
+
pool.resize(Math.max(newWidth, width), Math.max(newHeight, height), {
|
|
671
|
+
direction: `${directionHeight}-${directionWidth}`,
|
|
672
|
+
});
|
|
673
|
+
|
|
674
|
+
pool.component.fixResizeRounding();
|
|
675
|
+
if (pool.component.laneSet) {
|
|
676
|
+
/* Expand any lanes within the pool */
|
|
677
|
+
pool.component.resizeLanes();
|
|
678
|
+
|
|
679
|
+
pool.component.sortedLanes().forEach(laneShape => {
|
|
680
|
+
store.commit('updateNodeBounds', {
|
|
681
|
+
node: laneShape.component.node,
|
|
682
|
+
bounds: laneShape.getBBox(),
|
|
683
|
+
});
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
pool.component.updateAnchorPointPosition();
|
|
687
|
+
store.commit('updateNodeBounds', {
|
|
688
|
+
node: pool.component.node,
|
|
689
|
+
bounds: pool.getBBox(),
|
|
690
|
+
});
|
|
691
|
+
this.$emit('save-state');
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
},
|
|
695
|
+
},
|
|
696
|
+
};
|
|
697
|
+
</script>
|
|
698
|
+
|
|
699
|
+
<style scoped>
|
|
700
|
+
.box {
|
|
701
|
+
border: 1px solid #5faaee;
|
|
702
|
+
position: absolute;
|
|
703
|
+
pointer-events: none;
|
|
704
|
+
}
|
|
705
|
+
</style>
|