@mx-sose-front/mx-sose-graph 1.1.1 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +103 -10
- package/dist/index.esm.js +6618 -5593
- package/dist/index.esm.js.map +1 -1
- package/dist/index.umd.js +7 -7
- package/dist/index.umd.js.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/{ContextMenu.vue → ContextMenu/ContextMenu.vue} +243 -70
- package/src/components/DiagramListTooltip/DiagramListTooltip.vue +138 -0
- package/src/components/Edge/Edge.vue +38 -49
- package/src/components/InteractionLayer.vue +432 -838
- package/src/components/Shape/Block.vue +8 -8
- package/src/components/ZoomSlider/ZoomSlider.vue +229 -0
- package/src/constants/index.ts +12 -0
- package/src/statics/icons/childIcons//351/241/271/347/233/256/351/241/272/345/272/217@3x.png +0 -0
- package/src/store/graphStore.ts +98 -21
- package/src/types/index.ts +14 -1
- package/src/types/interactionLayer.ts +35 -0
- package/src/utils/contextMenuUtils.ts +264 -0
- package/src/utils/diagram.ts +93 -4
- package/src/utils/edgeUtils.ts +228 -0
- package/src/utils/geom.ts +34 -0
- package/src/utils/graphDragService.ts +14 -17
- package/src/utils/keyboardUtils.ts +229 -0
- package/src/utils/license-guard.ts +50 -0
- package/src/utils/nameEditUtils.ts +132 -0
- package/src/utils/resizeUtils.ts +463 -0
- package/src/view/graph.vue +102 -134
- package/src/components/Label.vue +0 -0
package/src/view/graph.vue
CHANGED
|
@@ -22,20 +22,27 @@
|
|
|
22
22
|
:actionButtonShapeDataId="actionButtonShapeId" @edit-name="handleEditName"
|
|
23
23
|
@update-shape="handleUpdateConnectShape" @diagramDoubleClick="handleDiagramDoubleClick"
|
|
24
24
|
@connect-end="handleConnectEnd" @action-button-click="handleActionButtonClick"
|
|
25
|
+
@object-flow-connect-end="handleObjectFlowConnectEnd"
|
|
25
26
|
@model-type-property-id-button-click="handleModelTypePropertyIdButtonClick" :lines="props.lines"
|
|
26
27
|
:packages="props.packages" :diagram="props.diagram" :tagged-value-labels="props.taggedValueLabels"
|
|
27
28
|
@action-button-add="handleActionButtonAdd" />
|
|
28
29
|
</div>
|
|
29
|
-
|
|
30
|
+
|
|
31
|
+
<!-- 所在图表 -->
|
|
32
|
+
<DiagramListTooltip :visible="tooltipVisible" :x="tooltipX" :y="tooltipY" :current-diagram-id="currentDiagramId"
|
|
33
|
+
@close="tooltipVisible = false" :diagram-location-data="chartLocationData || []" />
|
|
34
|
+
|
|
30
35
|
<!-- 缩放条 -->
|
|
31
|
-
<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
<ZoomSlider
|
|
37
|
+
v-model="zoomValue"
|
|
38
|
+
:min="0.1"
|
|
39
|
+
:max="3"
|
|
40
|
+
:step="0.1"
|
|
41
|
+
@zoom-in="handleZoomIn"
|
|
42
|
+
@zoom-out="handleZoomOut"
|
|
43
|
+
@scale-change="handleScaleChange"
|
|
44
|
+
v-if="graphStore.canOperate"
|
|
45
|
+
/>
|
|
39
46
|
</div>
|
|
40
47
|
</template>
|
|
41
48
|
|
|
@@ -43,7 +50,7 @@
|
|
|
43
50
|
import { ref, onMounted, computed, watch, nextTick, onUnmounted } from 'vue'
|
|
44
51
|
import normalizeWheel from 'normalize-wheel-es'
|
|
45
52
|
import InteractionLayer from '../components/InteractionLayer.vue'
|
|
46
|
-
import type { Shape } from '../types'
|
|
53
|
+
import type { locationChart, Shape } from '../types'
|
|
47
54
|
import { useGraphStore } from '../store/graphStore'
|
|
48
55
|
// 导入组件
|
|
49
56
|
import StrategicTaxonomyDiagram from '../components/Diagram/StrategicTaxonomyDiagram.vue'
|
|
@@ -63,6 +70,9 @@ import { getShapeComponent, getShapeStyle } from "../render/shape-renderer";
|
|
|
63
70
|
import { ShapeConfig } from '../utils/diagram'
|
|
64
71
|
import { setCompartmentZones, buildZones, setTaggedValueLabelsCache, setPackageTypesCache } from '../utils/compartment'
|
|
65
72
|
import { eventBus } from "../store";
|
|
73
|
+
import { guardOperate } from "../utils/license-guard"
|
|
74
|
+
import DiagramListTooltip from '../components/DiagramListTooltip/DiagramListTooltip.vue';
|
|
75
|
+
import ZoomSlider from '../components/ZoomSlider/ZoomSlider.vue'
|
|
66
76
|
|
|
67
77
|
registerShapes({
|
|
68
78
|
StrategicTaxonomyDiagram,
|
|
@@ -79,12 +89,19 @@ registerShapes({
|
|
|
79
89
|
Port
|
|
80
90
|
})
|
|
81
91
|
const interactionLayerRef = ref<InstanceType<typeof InteractionLayer> | null>(null)
|
|
92
|
+
|
|
93
|
+
// 所在图表弹窗相关变量
|
|
94
|
+
const tooltipVisible = ref(false)
|
|
95
|
+
const tooltipX = ref(0)
|
|
96
|
+
const tooltipY = ref(0)
|
|
97
|
+
const currentDiagramId = ref<string>('')
|
|
98
|
+
|
|
82
99
|
const props = defineProps<{
|
|
83
100
|
addShapeData: Shape,
|
|
84
101
|
connectShapeData: Shape,
|
|
85
|
-
lines:
|
|
102
|
+
lines: string[],
|
|
86
103
|
packages: string[],
|
|
87
|
-
diagram:
|
|
104
|
+
diagram: string[],
|
|
88
105
|
taggedValueLabels: string[],
|
|
89
106
|
actionButtonShapeId?: string,
|
|
90
107
|
classMetaTypes: string[],
|
|
@@ -92,12 +109,15 @@ const props = defineProps<{
|
|
|
92
109
|
pins: string[],
|
|
93
110
|
referentialAttributeModel: string[],
|
|
94
111
|
ports: string[],
|
|
112
|
+
canOperate: boolean
|
|
113
|
+
chartLocationData?: locationChart[] | null,
|
|
95
114
|
}>()
|
|
96
115
|
|
|
97
116
|
const emit = defineEmits<{
|
|
98
117
|
(e: 'shapes-property', value: { selectedShape: Shape, showPropertyPanel: boolean }): void
|
|
99
|
-
(e: 'shapes-edit-name', value: { shape: Shape, newName: string }): void
|
|
118
|
+
(e: 'shapes-edit-name', value: { shape: Shape, newName: string, oldName: string }): void
|
|
100
119
|
(e: 'connect-end', value: { sourceId: string, targetId: string, sourcePoint: { x: number, y: number }, targetPoint: { x: number, y: number }, waypoints: Array<{ x: number, y: number }> }): void
|
|
120
|
+
(e: 'object-flow-connect-end', value: { connectionData: { sourceId: string; targetId: string; sourcePoint: { x: number; y: number }; targetPoint: { x: number; y: number }; waypoints: Array<{ x: number; y: number }> }, outputPinBounds: { x: number; y: number; width: number; height: number }, inputPinBounds: { x: number; y: number; width: number; height: number } }): void
|
|
101
121
|
(e: 'action-button-click', value: string, shape: Shape): void
|
|
102
122
|
(e: 'diagramDoubleClick', data: any): void
|
|
103
123
|
(e: 'model-type-property-id-button-click', value: string, shape: Shape): void
|
|
@@ -120,13 +140,14 @@ watch(currentScale, (newScale) => {
|
|
|
120
140
|
})
|
|
121
141
|
|
|
122
142
|
// 处理缩放滑块变化
|
|
123
|
-
const
|
|
124
|
-
graphStore.setScale(
|
|
125
|
-
emit('scale-changed',
|
|
143
|
+
const handleScaleChange = (scale: number) => {
|
|
144
|
+
graphStore.setScale(scale)
|
|
145
|
+
emit('scale-changed', scale)
|
|
126
146
|
}
|
|
127
147
|
|
|
128
148
|
// 处理放大按钮点击
|
|
129
149
|
const handleZoomIn = () => {
|
|
150
|
+
// ZoomSlider组件已经处理了内部逻辑,这里只需要触发外部事件
|
|
130
151
|
const newScale = Math.min(currentScale.value + 0.1, 3)
|
|
131
152
|
graphStore.setScale(newScale)
|
|
132
153
|
emit('scale-changed', newScale)
|
|
@@ -134,6 +155,7 @@ const handleZoomIn = () => {
|
|
|
134
155
|
|
|
135
156
|
// 处理缩小按钮点击
|
|
136
157
|
const handleZoomOut = () => {
|
|
158
|
+
// ZoomSlider组件已经处理了内部逻辑,这里只需要触发外部事件
|
|
137
159
|
const newScale = Math.max(currentScale.value - 0.1, 0.1)
|
|
138
160
|
graphStore.setScale(newScale)
|
|
139
161
|
emit('scale-changed', newScale)
|
|
@@ -187,12 +209,14 @@ const handleNameClick = (shape: Shape, event: MouseEvent) => {
|
|
|
187
209
|
|
|
188
210
|
// 处理图形点击事件
|
|
189
211
|
const handleShapeClick = (shape: Shape, event: MouseEvent) => {
|
|
190
|
-
|
|
212
|
+
return guardOperate(async () => {
|
|
213
|
+
graphStore.selectShape(shape)
|
|
214
|
+
})
|
|
191
215
|
}
|
|
192
216
|
|
|
193
217
|
// 处理编辑名称事件
|
|
194
|
-
const handleEditName = (shape: Shape, newName: string) => {
|
|
195
|
-
emit('shapes-edit-name', { shape, newName })
|
|
218
|
+
const handleEditName = (shape: Shape, newName: string, oldName: string) => {
|
|
219
|
+
emit('shapes-edit-name', { shape, newName, oldName })
|
|
196
220
|
}
|
|
197
221
|
|
|
198
222
|
// 处理连接点位置更新
|
|
@@ -209,6 +233,10 @@ const handleConnectEnd = (connectionData: { sourceId: string; targetId: string;
|
|
|
209
233
|
console.log('连接结束事件已传递给父组件:', connectionData);
|
|
210
234
|
}
|
|
211
235
|
|
|
236
|
+
const handleObjectFlowConnectEnd = (connectionData: { connectionData: { sourceId: string; targetId: string; sourcePoint: { x: number; y: number }; targetPoint: { x: number; y: number }; waypoints: Array<{ x: number; y: number }> }, outputPinBounds: { x: number; y: number; width: number; height: number }, inputPinBounds: { x: number; y: number; width: number; height: number } }) => {
|
|
237
|
+
emit('object-flow-connect-end', connectionData);
|
|
238
|
+
}
|
|
239
|
+
|
|
212
240
|
// 处理双击图表事件
|
|
213
241
|
const handleDiagramDoubleClick = (data: any) => {
|
|
214
242
|
emit('diagramDoubleClick', data);
|
|
@@ -247,38 +275,48 @@ const handleEdgeClick = (shape: Shape, event: MouseEvent) => {
|
|
|
247
275
|
interactionLayerRef.value.handleEdgeClick(edgeShape, event);
|
|
248
276
|
}
|
|
249
277
|
}
|
|
278
|
+
|
|
279
|
+
// 处理所在图表弹窗位置信息
|
|
280
|
+
const handleLocateChartPosition = (position: { x: number, y: number }) => {
|
|
281
|
+
tooltipX.value = position.x;
|
|
282
|
+
tooltipY.value = position.y;
|
|
283
|
+
tooltipVisible.value = true;
|
|
284
|
+
}
|
|
285
|
+
|
|
250
286
|
const handleActionButtonAdd = (shape: Shape) => {
|
|
251
287
|
emit('action-button-add', shape);
|
|
252
288
|
}
|
|
253
289
|
|
|
254
290
|
// 处理鼠标滚轮事件,实现缩放功能
|
|
255
291
|
const handleWheel = (event: WheelEvent) => {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
292
|
+
return guardOperate(async () => {
|
|
293
|
+
// 只有按住Ctrl键时才执行缩放
|
|
294
|
+
if (!event.ctrlKey && !event.metaKey) {
|
|
295
|
+
// 不按住Ctrl键时,允许默认的滚轮行为(滚动)
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
261
298
|
|
|
262
|
-
|
|
263
|
-
|
|
299
|
+
// 阻止默认行为,避免页面缩放
|
|
300
|
+
event.preventDefault();
|
|
264
301
|
|
|
265
|
-
|
|
266
|
-
|
|
302
|
+
// 使用normalize-wheel-es标准化滚轮事件
|
|
303
|
+
const normalized = normalizeWheel(event);
|
|
267
304
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
305
|
+
// 计算缩放比例增量
|
|
306
|
+
const zoomFactor = 0.01;
|
|
307
|
+
const delta = normalized.pixelY > 0 ? -zoomFactor : zoomFactor;
|
|
271
308
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
309
|
+
// 获取当前缩放比例并计算新的缩放比例
|
|
310
|
+
// getScale默认使用activeDiagramId
|
|
311
|
+
const currentScale = graphStore.getScale();
|
|
312
|
+
const newScale = currentScale + delta;
|
|
276
313
|
|
|
277
|
-
|
|
278
|
-
|
|
314
|
+
// 设置新的缩放比例,默认使用activeDiagramId
|
|
315
|
+
graphStore.setScale(newScale);
|
|
279
316
|
|
|
280
|
-
|
|
281
|
-
|
|
317
|
+
// 通知父组件缩放变化
|
|
318
|
+
emit('scale-changed', newScale);
|
|
319
|
+
})
|
|
282
320
|
}
|
|
283
321
|
|
|
284
322
|
const updateShapes = (shapes: Shape[]) => {
|
|
@@ -376,17 +414,26 @@ watch(
|
|
|
376
414
|
)
|
|
377
415
|
// 把 referentialAttributeModel + pins 合并后存进 store
|
|
378
416
|
watch(
|
|
379
|
-
() => [props.referentialAttributeModel, props.pins,props.ports],
|
|
417
|
+
() => [props.referentialAttributeModel, props.pins, props.ports],
|
|
380
418
|
([referentialAttributeModel, pins]) => {
|
|
381
419
|
const refArr = referentialAttributeModel ?? []
|
|
382
420
|
const pinArr = pins ?? []
|
|
383
|
-
const portArr = props.ports ?? []
|
|
421
|
+
const portArr = props.ports ?? []
|
|
384
422
|
graphStore.pinsTypes = pinArr
|
|
385
423
|
graphStore.portsTypes = portArr
|
|
386
|
-
graphStore.ownerRequiredShapeKeys = [...refArr, ...pinArr
|
|
424
|
+
graphStore.ownerRequiredShapeKeys = [...refArr, ...pinArr, ...portArr]
|
|
387
425
|
},
|
|
388
426
|
{ immediate: true }
|
|
389
427
|
)
|
|
428
|
+
watch(
|
|
429
|
+
() => props.canOperate,
|
|
430
|
+
(val) => {
|
|
431
|
+
graphStore.canOperate = val ?? false
|
|
432
|
+
},
|
|
433
|
+
{
|
|
434
|
+
immediate: true,
|
|
435
|
+
}
|
|
436
|
+
)
|
|
390
437
|
onMounted(() => {
|
|
391
438
|
initShapes()
|
|
392
439
|
document.addEventListener('keydown', (e) => {
|
|
@@ -396,6 +443,8 @@ onMounted(() => {
|
|
|
396
443
|
}
|
|
397
444
|
});
|
|
398
445
|
|
|
446
|
+
// 监听所在图表弹窗位置信息事件
|
|
447
|
+
eventBus.on('locate-chart-position', handleLocateChartPosition)
|
|
399
448
|
})
|
|
400
449
|
|
|
401
450
|
onUnmounted(() => {
|
|
@@ -405,6 +454,9 @@ onUnmounted(() => {
|
|
|
405
454
|
graphStore.selectedIds = []
|
|
406
455
|
}
|
|
407
456
|
});
|
|
457
|
+
|
|
458
|
+
// 移除所在图表弹窗位置信息事件监听器
|
|
459
|
+
eventBus.off('locate-chart-position', handleLocateChartPosition)
|
|
408
460
|
})
|
|
409
461
|
|
|
410
462
|
defineExpose({
|
|
@@ -453,105 +505,21 @@ defineExpose({
|
|
|
453
505
|
position: absolute;
|
|
454
506
|
}
|
|
455
507
|
|
|
456
|
-
/*
|
|
457
|
-
.zoom-bar {
|
|
458
|
-
position: absolute;
|
|
459
|
-
bottom: 0;
|
|
460
|
-
right: 0;
|
|
461
|
-
left: 0;
|
|
462
|
-
width: 100%;
|
|
463
|
-
height: 24px;
|
|
464
|
-
display: flex;
|
|
465
|
-
align-items: center;
|
|
466
|
-
justify-content: flex-end;
|
|
467
|
-
background: white;
|
|
468
|
-
border-top: 1px solid #e0e0e0;
|
|
469
|
-
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.05);
|
|
470
|
-
z-index: 1000;
|
|
471
|
-
gap: 6px;
|
|
472
|
-
padding: 0 10px;
|
|
473
|
-
}
|
|
474
|
-
|
|
508
|
+
/* 缩放百分比显示 */
|
|
475
509
|
.zoom-level {
|
|
510
|
+
position: absolute;
|
|
511
|
+
bottom: 30px;
|
|
512
|
+
right: 15px;
|
|
476
513
|
font-size: 10px;
|
|
477
514
|
font-weight: 500;
|
|
478
515
|
min-width: 35px;
|
|
479
516
|
text-align: center;
|
|
480
517
|
color: #333;
|
|
518
|
+
background: rgba(255, 255, 255, 0.9);
|
|
519
|
+
padding: 2px 6px;
|
|
520
|
+
border-radius: 3px;
|
|
521
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
481
522
|
}
|
|
482
523
|
|
|
483
|
-
.zoom-slider {
|
|
484
|
-
width: 150px;
|
|
485
|
-
height: 100%;
|
|
486
|
-
display: flex;
|
|
487
|
-
align-items: center;
|
|
488
|
-
justify-content: center;
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
.zoom-slider input[type="range"] {
|
|
492
|
-
width: 100%;
|
|
493
|
-
height: 2px;
|
|
494
|
-
border-radius: 1px;
|
|
495
|
-
background: #e0e0e0;
|
|
496
|
-
outline: none;
|
|
497
|
-
-webkit-appearance: none;
|
|
498
|
-
margin: 0;
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
.zoom-slider input[type="range"]::-webkit-slider-thumb {
|
|
502
|
-
-webkit-appearance: none;
|
|
503
|
-
appearance: none;
|
|
504
|
-
width: 10px;
|
|
505
|
-
height: 10px;
|
|
506
|
-
border-radius: 50%;
|
|
507
|
-
background: #1890ff;
|
|
508
|
-
cursor: pointer;
|
|
509
|
-
transition: all 0.2s;
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
.zoom-slider input[type="range"]::-webkit-slider-thumb:hover {
|
|
513
|
-
background: #40a9ff;
|
|
514
|
-
transform: scale(1.1);
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
.zoom-slider input[type="range"]::-moz-range-thumb {
|
|
518
|
-
width: 10px;
|
|
519
|
-
height: 10px;
|
|
520
|
-
border-radius: 50%;
|
|
521
|
-
background: #1890ff;
|
|
522
|
-
cursor: pointer;
|
|
523
|
-
border: none;
|
|
524
|
-
transition: all 0.2s;
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
.zoom-slider input[type="range"]::-moz-range-thumb:hover {
|
|
528
|
-
background: #40a9ff;
|
|
529
|
-
transform: scale(1.1);
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
.zoom-button {
|
|
533
|
-
width: 18px;
|
|
534
|
-
height: 18px;
|
|
535
|
-
display: flex;
|
|
536
|
-
align-items: center;
|
|
537
|
-
justify-content: center;
|
|
538
|
-
border: 1px solid #e0e0e0;
|
|
539
|
-
border-radius: 2px;
|
|
540
|
-
background: white;
|
|
541
|
-
cursor: pointer;
|
|
542
|
-
font-size: 10px;
|
|
543
|
-
font-weight: 600;
|
|
544
|
-
color: #333;
|
|
545
|
-
transition: all 0.2s;
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
.zoom-button:hover {
|
|
549
|
-
background: #f5f5f5;
|
|
550
|
-
border-color: #1890ff;
|
|
551
|
-
color: #1890ff;
|
|
552
|
-
}
|
|
553
524
|
|
|
554
|
-
.zoom-button:active {
|
|
555
|
-
background: #e6f7ff;
|
|
556
|
-
}
|
|
557
525
|
</style>
|
package/src/components/Label.vue
DELETED
|
File without changes
|