@mx-sose-front/mx-sose-graph 1.1.0 → 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 +6620 -5599
- 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 -136
- 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
|
|
@@ -106,8 +126,6 @@ const emit = defineEmits<{
|
|
|
106
126
|
}>()
|
|
107
127
|
|
|
108
128
|
const graphStore = useGraphStore()
|
|
109
|
-
const diagramContentRef = ref<HTMLElement | null>(null)
|
|
110
|
-
const shapeComponents = ref<any[]>([]) // 用于获取子组件实例
|
|
111
129
|
const resShape = ref<Shape>({} as Shape) // 用于存储通过 ref 获取的 shape 数据
|
|
112
130
|
|
|
113
131
|
// 计算属性:获取当前画布的缩放比例
|
|
@@ -122,13 +140,14 @@ watch(currentScale, (newScale) => {
|
|
|
122
140
|
})
|
|
123
141
|
|
|
124
142
|
// 处理缩放滑块变化
|
|
125
|
-
const
|
|
126
|
-
graphStore.setScale(
|
|
127
|
-
emit('scale-changed',
|
|
143
|
+
const handleScaleChange = (scale: number) => {
|
|
144
|
+
graphStore.setScale(scale)
|
|
145
|
+
emit('scale-changed', scale)
|
|
128
146
|
}
|
|
129
147
|
|
|
130
148
|
// 处理放大按钮点击
|
|
131
149
|
const handleZoomIn = () => {
|
|
150
|
+
// ZoomSlider组件已经处理了内部逻辑,这里只需要触发外部事件
|
|
132
151
|
const newScale = Math.min(currentScale.value + 0.1, 3)
|
|
133
152
|
graphStore.setScale(newScale)
|
|
134
153
|
emit('scale-changed', newScale)
|
|
@@ -136,6 +155,7 @@ const handleZoomIn = () => {
|
|
|
136
155
|
|
|
137
156
|
// 处理缩小按钮点击
|
|
138
157
|
const handleZoomOut = () => {
|
|
158
|
+
// ZoomSlider组件已经处理了内部逻辑,这里只需要触发外部事件
|
|
139
159
|
const newScale = Math.max(currentScale.value - 0.1, 0.1)
|
|
140
160
|
graphStore.setScale(newScale)
|
|
141
161
|
emit('scale-changed', newScale)
|
|
@@ -189,12 +209,14 @@ const handleNameClick = (shape: Shape, event: MouseEvent) => {
|
|
|
189
209
|
|
|
190
210
|
// 处理图形点击事件
|
|
191
211
|
const handleShapeClick = (shape: Shape, event: MouseEvent) => {
|
|
192
|
-
|
|
212
|
+
return guardOperate(async () => {
|
|
213
|
+
graphStore.selectShape(shape)
|
|
214
|
+
})
|
|
193
215
|
}
|
|
194
216
|
|
|
195
217
|
// 处理编辑名称事件
|
|
196
|
-
const handleEditName = (shape: Shape, newName: string) => {
|
|
197
|
-
emit('shapes-edit-name', { shape, newName })
|
|
218
|
+
const handleEditName = (shape: Shape, newName: string, oldName: string) => {
|
|
219
|
+
emit('shapes-edit-name', { shape, newName, oldName })
|
|
198
220
|
}
|
|
199
221
|
|
|
200
222
|
// 处理连接点位置更新
|
|
@@ -211,6 +233,10 @@ const handleConnectEnd = (connectionData: { sourceId: string; targetId: string;
|
|
|
211
233
|
console.log('连接结束事件已传递给父组件:', connectionData);
|
|
212
234
|
}
|
|
213
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
|
+
|
|
214
240
|
// 处理双击图表事件
|
|
215
241
|
const handleDiagramDoubleClick = (data: any) => {
|
|
216
242
|
emit('diagramDoubleClick', data);
|
|
@@ -249,38 +275,48 @@ const handleEdgeClick = (shape: Shape, event: MouseEvent) => {
|
|
|
249
275
|
interactionLayerRef.value.handleEdgeClick(edgeShape, event);
|
|
250
276
|
}
|
|
251
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
|
+
|
|
252
286
|
const handleActionButtonAdd = (shape: Shape) => {
|
|
253
287
|
emit('action-button-add', shape);
|
|
254
288
|
}
|
|
255
289
|
|
|
256
290
|
// 处理鼠标滚轮事件,实现缩放功能
|
|
257
291
|
const handleWheel = (event: WheelEvent) => {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
292
|
+
return guardOperate(async () => {
|
|
293
|
+
// 只有按住Ctrl键时才执行缩放
|
|
294
|
+
if (!event.ctrlKey && !event.metaKey) {
|
|
295
|
+
// 不按住Ctrl键时,允许默认的滚轮行为(滚动)
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
263
298
|
|
|
264
|
-
|
|
265
|
-
|
|
299
|
+
// 阻止默认行为,避免页面缩放
|
|
300
|
+
event.preventDefault();
|
|
266
301
|
|
|
267
|
-
|
|
268
|
-
|
|
302
|
+
// 使用normalize-wheel-es标准化滚轮事件
|
|
303
|
+
const normalized = normalizeWheel(event);
|
|
269
304
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
305
|
+
// 计算缩放比例增量
|
|
306
|
+
const zoomFactor = 0.01;
|
|
307
|
+
const delta = normalized.pixelY > 0 ? -zoomFactor : zoomFactor;
|
|
273
308
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
309
|
+
// 获取当前缩放比例并计算新的缩放比例
|
|
310
|
+
// getScale默认使用activeDiagramId
|
|
311
|
+
const currentScale = graphStore.getScale();
|
|
312
|
+
const newScale = currentScale + delta;
|
|
278
313
|
|
|
279
|
-
|
|
280
|
-
|
|
314
|
+
// 设置新的缩放比例,默认使用activeDiagramId
|
|
315
|
+
graphStore.setScale(newScale);
|
|
281
316
|
|
|
282
|
-
|
|
283
|
-
|
|
317
|
+
// 通知父组件缩放变化
|
|
318
|
+
emit('scale-changed', newScale);
|
|
319
|
+
})
|
|
284
320
|
}
|
|
285
321
|
|
|
286
322
|
const updateShapes = (shapes: Shape[]) => {
|
|
@@ -378,17 +414,26 @@ watch(
|
|
|
378
414
|
)
|
|
379
415
|
// 把 referentialAttributeModel + pins 合并后存进 store
|
|
380
416
|
watch(
|
|
381
|
-
() => [props.referentialAttributeModel, props.pins,props.ports],
|
|
417
|
+
() => [props.referentialAttributeModel, props.pins, props.ports],
|
|
382
418
|
([referentialAttributeModel, pins]) => {
|
|
383
419
|
const refArr = referentialAttributeModel ?? []
|
|
384
420
|
const pinArr = pins ?? []
|
|
385
|
-
const portArr = props.ports ?? []
|
|
421
|
+
const portArr = props.ports ?? []
|
|
386
422
|
graphStore.pinsTypes = pinArr
|
|
387
423
|
graphStore.portsTypes = portArr
|
|
388
|
-
graphStore.ownerRequiredShapeKeys = [...refArr, ...pinArr
|
|
424
|
+
graphStore.ownerRequiredShapeKeys = [...refArr, ...pinArr, ...portArr]
|
|
389
425
|
},
|
|
390
426
|
{ immediate: true }
|
|
391
427
|
)
|
|
428
|
+
watch(
|
|
429
|
+
() => props.canOperate,
|
|
430
|
+
(val) => {
|
|
431
|
+
graphStore.canOperate = val ?? false
|
|
432
|
+
},
|
|
433
|
+
{
|
|
434
|
+
immediate: true,
|
|
435
|
+
}
|
|
436
|
+
)
|
|
392
437
|
onMounted(() => {
|
|
393
438
|
initShapes()
|
|
394
439
|
document.addEventListener('keydown', (e) => {
|
|
@@ -398,6 +443,8 @@ onMounted(() => {
|
|
|
398
443
|
}
|
|
399
444
|
});
|
|
400
445
|
|
|
446
|
+
// 监听所在图表弹窗位置信息事件
|
|
447
|
+
eventBus.on('locate-chart-position', handleLocateChartPosition)
|
|
401
448
|
})
|
|
402
449
|
|
|
403
450
|
onUnmounted(() => {
|
|
@@ -407,6 +454,9 @@ onUnmounted(() => {
|
|
|
407
454
|
graphStore.selectedIds = []
|
|
408
455
|
}
|
|
409
456
|
});
|
|
457
|
+
|
|
458
|
+
// 移除所在图表弹窗位置信息事件监听器
|
|
459
|
+
eventBus.off('locate-chart-position', handleLocateChartPosition)
|
|
410
460
|
})
|
|
411
461
|
|
|
412
462
|
defineExpose({
|
|
@@ -455,105 +505,21 @@ defineExpose({
|
|
|
455
505
|
position: absolute;
|
|
456
506
|
}
|
|
457
507
|
|
|
458
|
-
/*
|
|
459
|
-
.zoom-bar {
|
|
460
|
-
position: absolute;
|
|
461
|
-
bottom: 0;
|
|
462
|
-
right: 0;
|
|
463
|
-
left: 0;
|
|
464
|
-
width: 100%;
|
|
465
|
-
height: 24px;
|
|
466
|
-
display: flex;
|
|
467
|
-
align-items: center;
|
|
468
|
-
justify-content: flex-end;
|
|
469
|
-
background: white;
|
|
470
|
-
border-top: 1px solid #e0e0e0;
|
|
471
|
-
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.05);
|
|
472
|
-
z-index: 1000;
|
|
473
|
-
gap: 6px;
|
|
474
|
-
padding: 0 10px;
|
|
475
|
-
}
|
|
476
|
-
|
|
508
|
+
/* 缩放百分比显示 */
|
|
477
509
|
.zoom-level {
|
|
510
|
+
position: absolute;
|
|
511
|
+
bottom: 30px;
|
|
512
|
+
right: 15px;
|
|
478
513
|
font-size: 10px;
|
|
479
514
|
font-weight: 500;
|
|
480
515
|
min-width: 35px;
|
|
481
516
|
text-align: center;
|
|
482
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);
|
|
483
522
|
}
|
|
484
523
|
|
|
485
|
-
.zoom-slider {
|
|
486
|
-
width: 150px;
|
|
487
|
-
height: 100%;
|
|
488
|
-
display: flex;
|
|
489
|
-
align-items: center;
|
|
490
|
-
justify-content: center;
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
.zoom-slider input[type="range"] {
|
|
494
|
-
width: 100%;
|
|
495
|
-
height: 2px;
|
|
496
|
-
border-radius: 1px;
|
|
497
|
-
background: #e0e0e0;
|
|
498
|
-
outline: none;
|
|
499
|
-
-webkit-appearance: none;
|
|
500
|
-
margin: 0;
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
.zoom-slider input[type="range"]::-webkit-slider-thumb {
|
|
504
|
-
-webkit-appearance: none;
|
|
505
|
-
appearance: none;
|
|
506
|
-
width: 10px;
|
|
507
|
-
height: 10px;
|
|
508
|
-
border-radius: 50%;
|
|
509
|
-
background: #1890ff;
|
|
510
|
-
cursor: pointer;
|
|
511
|
-
transition: all 0.2s;
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
.zoom-slider input[type="range"]::-webkit-slider-thumb:hover {
|
|
515
|
-
background: #40a9ff;
|
|
516
|
-
transform: scale(1.1);
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
.zoom-slider input[type="range"]::-moz-range-thumb {
|
|
520
|
-
width: 10px;
|
|
521
|
-
height: 10px;
|
|
522
|
-
border-radius: 50%;
|
|
523
|
-
background: #1890ff;
|
|
524
|
-
cursor: pointer;
|
|
525
|
-
border: none;
|
|
526
|
-
transition: all 0.2s;
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
.zoom-slider input[type="range"]::-moz-range-thumb:hover {
|
|
530
|
-
background: #40a9ff;
|
|
531
|
-
transform: scale(1.1);
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
.zoom-button {
|
|
535
|
-
width: 18px;
|
|
536
|
-
height: 18px;
|
|
537
|
-
display: flex;
|
|
538
|
-
align-items: center;
|
|
539
|
-
justify-content: center;
|
|
540
|
-
border: 1px solid #e0e0e0;
|
|
541
|
-
border-radius: 2px;
|
|
542
|
-
background: white;
|
|
543
|
-
cursor: pointer;
|
|
544
|
-
font-size: 10px;
|
|
545
|
-
font-weight: 600;
|
|
546
|
-
color: #333;
|
|
547
|
-
transition: all 0.2s;
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
.zoom-button:hover {
|
|
551
|
-
background: #f5f5f5;
|
|
552
|
-
border-color: #1890ff;
|
|
553
|
-
color: #1890ff;
|
|
554
|
-
}
|
|
555
524
|
|
|
556
|
-
.zoom-button:active {
|
|
557
|
-
background: #e6f7ff;
|
|
558
|
-
}
|
|
559
525
|
</style>
|
package/src/components/Label.vue
DELETED
|
File without changes
|