@zhangqingcq/vgce 0.0.24 → 0.0.26

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhangqingcq/vgce",
3
- "version": "0.0.24",
3
+ "version": "0.0.26",
4
4
  "description": "Vector graphics configure editor. svg组态编辑器。基于vue3.3+ts+element-plus+vite",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -65,6 +65,11 @@ export const connection_line_system: ISystemStraightLine = {
65
65
  type: EConfigItemPropsType.InputNumber,
66
66
  val: 2
67
67
  },
68
+ point_r: {
69
+ title: '节点半径',
70
+ type: EConfigItemPropsType.InputNumber,
71
+ val: 4
72
+ },
68
73
  point_position: {
69
74
  title: '点坐标',
70
75
  type: EConfigItemPropsType.JsonEdit,
@@ -57,7 +57,8 @@
57
57
  const ct: Record<string, any> = {
58
58
  MoveCanvas: 'grab',
59
59
  Rotate: "url('/src/assets/icons/rotate.svg'), auto",
60
- Connection: 'crosshair'
60
+ Connection: 'crosshair',
61
+ SetConnectionLineNode: 'crosshair'
61
62
  }
62
63
  const cursor_style = computed(() => {
63
64
  if (Object.keys(ct).indexOf(globalStore.intention) > -1) {
@@ -119,6 +120,7 @@
119
120
  })
120
121
 
121
122
  let groupMoved = false
123
+ let lineNodeMoved = false
122
124
 
123
125
  const dropEvent = (e: Record<string, any>) => {
124
126
  if (globalStore.intention == EGlobalStoreIntention.None) {
@@ -342,6 +344,7 @@
342
344
  (globalStore.intention === EGlobalStoreIntention.Select || globalStore.intention === EGlobalStoreIntention.Move)
343
345
  ) {
344
346
  //有选中组件 移动单个组件
347
+ //todo 对齐功能开发
345
348
  globalStore.handle_svg_info.info.x = x
346
349
 
347
350
  globalStore.handle_svg_info.info.y = y
@@ -559,8 +562,9 @@
559
562
  const _y =
560
563
  globalStore.mouse_info.new_position_y - globalStore.mouse_info.position_y - svgEditLayoutStore.center_offset.y
561
564
  const brotherPoint = globalStore.handle_svg_info.info.props.point_position.val[l - 2]
562
- let ox = brotherPoint.x < _x ? -5 : brotherPoint.x > _x ? 5 : 0
563
- let oy = brotherPoint.y < _y ? -5 : brotherPoint.y > _y ? 5 : 0
565
+ const pr = globalStore.handle_svg_info?.info.props.point_r?.val + 2 || 4
566
+ let ox = brotherPoint.x < _x ? -pr : brotherPoint.x > _x ? pr : 0
567
+ let oy = brotherPoint.y < _y ? -pr : brotherPoint.y > _y ? pr : 0
564
568
  if (e.ctrlKey) {
565
569
  //画竖线
566
570
  globalStore.handle_svg_info.info.props.point_position.val[l - 1] = {
@@ -580,17 +584,32 @@
580
584
  }
581
585
  }
582
586
  } else if (globalStore.intention === EGlobalStoreIntention.SetConnectionLineNode && globalStore.handle_svg_info) {
587
+ if (
588
+ !lineNodeMoved &&
589
+ (globalStore.connection_line_node_info.point_index ===
590
+ globalStore.handle_svg_info.info.props.point_position.val.length - 1 ||
591
+ globalStore.connection_line_node_info.point_index === 0)
592
+ ) {
593
+ lineNodeMoved = true
594
+ }
595
+ const l = globalStore.handle_svg_info?.info.props.point_position.val.length
596
+ const _x = getSvgNowPosition(
597
+ globalStore.mouse_info.position_x,
598
+ globalStore.mouse_info.new_position_x,
599
+ globalStore.connection_line_node_info.init_pos.x
600
+ )
601
+ const _y = getSvgNowPosition(
602
+ globalStore.mouse_info.position_y,
603
+ globalStore.mouse_info.new_position_y,
604
+ globalStore.connection_line_node_info.init_pos.y
605
+ )
606
+ const brotherPoint = globalStore.handle_svg_info.info.props.point_position.val[l - 2]
607
+ const pr = globalStore.handle_svg_info?.info.props.point_r?.val + 2 || 4
608
+ let ox = brotherPoint.x < _x ? -pr : brotherPoint.x > _x ? pr : 0
609
+ let oy = brotherPoint.y < _y ? -pr : brotherPoint.y > _y ? pr : 0
583
610
  globalStore.handle_svg_info.info.props.point_position.val[globalStore.connection_line_node_info.point_index] = {
584
- x: getSvgNowPosition(
585
- globalStore.mouse_info.position_x,
586
- globalStore.mouse_info.new_position_x,
587
- globalStore.connection_line_node_info.init_pos.x
588
- ),
589
- y: getSvgNowPosition(
590
- globalStore.mouse_info.position_y,
591
- globalStore.mouse_info.new_position_y,
592
- globalStore.connection_line_node_info.init_pos.y
593
- )
611
+ x: _x + ox,
612
+ y: _y + oy
594
613
  }
595
614
  }
596
615
  }
@@ -631,6 +650,17 @@
631
650
  globalStore.intention = EGlobalStoreIntention.None
632
651
  } else if (globalStore.intention === EGlobalStoreIntention.Connection) {
633
652
  return
653
+ } else if (globalStore.intention === EGlobalStoreIntention.SetConnectionLineNode) {
654
+ //解绑锚点
655
+ if (lineNodeMoved && globalStore.handle_svg_info?.info.bind_anchors) {
656
+ if (globalStore.connection_line_node_info.point_index === 0) {
657
+ globalStore.handle_svg_info.info.bind_anchors.start = null
658
+ } else {
659
+ globalStore.handle_svg_info.info.bind_anchors.end = null
660
+ }
661
+ }
662
+ globalStore.intention = EGlobalStoreIntention.None
663
+ lineNodeMoved = false
634
664
  } else if (globalStore.intention === EGlobalStoreIntention.SelectArea) {
635
665
  //框选
636
666
  globalStore.setHandleSvgInfo(null)
@@ -654,7 +684,6 @@
654
684
  contextMenuStore.display = false
655
685
  }
656
686
  const onCanvasMouseDown = (e: MouseEvent) => {
657
- //todo 画横线或垂线
658
687
  const { clientX, clientY } = e
659
688
  if (globalStore.intention === EGlobalStoreIntention.Connection) {
660
689
  if (!globalStore.handle_svg_info) {
@@ -1089,20 +1118,20 @@
1089
1118
  />
1090
1119
  </g>
1091
1120
  </svg>
1092
- <!-- 右键菜单 -->
1093
- <ul ref="contextMenuRef" class="contextMenu" v-show="contextMenuStore.display">
1094
- <li
1095
- v-for="(item, key) in contextMenuStore.info"
1096
- :key="item.title"
1097
- @click="contextMenuStore.onContextMenuClick(key)"
1098
- >
1099
- <p :class="item.enable ? '' : 'disabled'">
1100
- {{ item.title }}
1101
- <span class="shortcut">{{ item.hot_key }}</span>
1102
- </p>
1103
- </li>
1104
- </ul>
1105
1121
  </div>
1122
+ <!-- 右键菜单 -->
1123
+ <ul ref="contextMenuRef" class="contextMenu" v-show="contextMenuStore.display">
1124
+ <li
1125
+ v-for="(item, key) in contextMenuStore.info"
1126
+ :key="item.title"
1127
+ @click="contextMenuStore.onContextMenuClick(key)"
1128
+ >
1129
+ <p :class="item.enable ? '' : 'disabled'">
1130
+ {{ item.title }}
1131
+ <span class="shortcut">{{ item.hot_key }}</span>
1132
+ </p>
1133
+ </li>
1134
+ </ul>
1106
1135
  </template>
1107
1136
 
1108
1137
  <style lang="less" scoped>
@@ -117,7 +117,7 @@
117
117
  :key="index"
118
118
  :cx="item.x"
119
119
  :cy="item.y"
120
- r="6"
120
+ :r="props.itemInfo.props.point_r.val"
121
121
  stroke-width="1"
122
122
  :stroke="props.itemInfo.props.stroke.val"
123
123
  fill="#fff"
@@ -73,11 +73,40 @@
73
73
  getCoordinateOffset(props.itemInfo.actual_bound.height, props.itemInfo.scale_y) +
74
74
  radius.value
75
75
  )
76
+
77
+ const anchorUp = (e: any, type: ELineBindAnchors) => {
78
+ if (globalStore.intention === EGlobalStoreIntention.SetConnectionLineNode) {
79
+ //移动连线首尾节点,绑定锚点
80
+ e.stopPropagation()
81
+ if (globalStore.handle_svg_info?.info.bind_anchors && globalStore.connection_line_node_info) {
82
+ if (globalStore.connection_line_node_info.point_index === 0) {
83
+ globalStore.handle_svg_info.info.bind_anchors.start = {
84
+ type: type,
85
+ target_id: props.itemInfo.id
86
+ }
87
+ } else if (
88
+ globalStore.connection_line_node_info.point_index ===
89
+ globalStore.handle_svg_info.info.props.point_position.val.length - 1
90
+ ) {
91
+ globalStore.handle_svg_info.info.bind_anchors.end = {
92
+ type: type,
93
+ target_id: props.itemInfo.id
94
+ }
95
+ }
96
+
97
+ globalStore.intention = EGlobalStoreIntention.None
98
+ globalStore.setHandleSvgInfo(null)
99
+ nextTick(function () {
100
+ moveAnchors(props.itemInfo)
101
+ })
102
+ }
103
+ }
104
+ }
76
105
  const bindAnchor = (e: any, type: ELineBindAnchors) => {
77
106
  if (globalStore.intention === EGlobalStoreIntention.None) {
78
107
  createLine(e, type, props.itemInfo)
79
108
  } else if (globalStore.intention === EGlobalStoreIntention.Connection) {
80
- //点击锚上在连线的情况下点击结束连线并绑定锚点
109
+ //在连线的情况下,点击锚点,结束连线并绑定锚点
81
110
  e.stopPropagation()
82
111
  if (globalStore.handle_svg_info?.info.bind_anchors) {
83
112
  globalStore.handle_svg_info.info.bind_anchors.end = {
@@ -102,19 +131,25 @@
102
131
  stroke-width="2"
103
132
  stroke="rgba(0,0,0,0)"
104
133
  >
105
- <g @mousedown="bindAnchor($event, ELineBindAnchors.TopCenter)">
134
+ <g
135
+ @mousedown="bindAnchor($event, ELineBindAnchors.TopCenter)"
136
+ @mouseup="anchorUp($event, ELineBindAnchors.TopCenter)"
137
+ >
106
138
  <circle class="out-circle" :cx="cxT" :cy="cyT" :r="outRadius" fill-opacity=".3" />
107
139
  <circle id="connection_tc" :cx="cxT" :cy="cyT" :r="radius" pointer-events="all" />
108
140
  </g>
109
- <g @mousedown="bindAnchor($event, ELineBindAnchors.Right)">
141
+ <g @mousedown="bindAnchor($event, ELineBindAnchors.Right)" @mouseup="anchorUp($event, ELineBindAnchors.Right)">
110
142
  <circle class="out-circle" :cx="cxR" :cy="cyR" :r="outRadius" fill-opacity=".3" />
111
143
  <circle id="connection_r" :cx="cxR" :cy="cyR" :r="radius" pointer-events="all" />
112
144
  </g>
113
- <g @mousedown="bindAnchor($event, ELineBindAnchors.BottomCenter)">
145
+ <g
146
+ @mousedown="bindAnchor($event, ELineBindAnchors.BottomCenter)"
147
+ @mouseup="anchorUp($event, ELineBindAnchors.BottomCenter)"
148
+ >
114
149
  <circle class="out-circle" :cx="cxB" :cy="cyB" :r="outRadius" fill-opacity=".3" />
115
150
  <circle id="connection_bc" :cx="cxB" :cy="cyB" :r="radius" pointer-events="all" />
116
151
  </g>
117
- <g @mousedown="bindAnchor($event, ELineBindAnchors.Left)">
152
+ <g @mousedown="bindAnchor($event, ELineBindAnchors.Left)" @mouseup="anchorUp($event, ELineBindAnchors.Left)">
118
153
  <circle class="out-circle" :cx="cxL" :cy="cyL" :r="outRadius" fill-opacity=".3" />
119
154
  <circle id="connection_l" :cx="cxL" :cy="cyL" :r="radius" :style="{ cursor: 'crosshair' }" pointer-events="all" />
120
155
  </g>
@@ -219,11 +219,11 @@
219
219
  <el-input v-model="globalStore.handle_svg_info!.info.id" />
220
220
  </el-form-item>
221
221
  <div
222
- v-for="(e, k) in globalStore.handle_svg_info!.info.state"
222
+ v-for="(e, k) of globalStore.handle_svg_info!.info.state"
223
223
  :key="'state' + String(k)"
224
224
  v-if="globalStore.handle_svg_info!.info.state"
225
225
  >
226
- <el-form-item class="props-row" :label="String(k)" size="small"> {{ e?.default }}</el-form-item>
226
+ <el-form-item class="props-row" :label="String(k)" size="small"> {{ e!.default }}</el-form-item>
227
227
 
228
228
  <el-form-item
229
229
  v-if="k === 'OnOff'"
@@ -243,6 +243,26 @@
243
243
  </el-form-item>
244
244
  </div>
245
245
  <dynamic-el-form-item :obj-info="globalStore.handle_svg_info!.info.props" code />
246
+ <el-form-item
247
+ :label="globalStore.handle_svg_info!.info.animations.type.title"
248
+ size="small"
249
+ v-if="globalStore.handle_svg_info!.info.animations"
250
+ >
251
+ <el-select v-model="globalStore.handle_svg_info!.info.animations.type.val" placeholder="Select" size="small">
252
+ <el-option
253
+ v-for="item in globalStore.handle_svg_info!.info.animations.type.options"
254
+ :key="item.value"
255
+ :label="item.label"
256
+ :value="item.value"
257
+ />
258
+ </el-select>
259
+ </el-form-item>
260
+
261
+ <dynamic-el-form-item
262
+ :obj-info="globalStore.handle_svg_info!.info.animations"
263
+ v-if="globalStore.handle_svg_info!.info.animations?.type.val !== 'None'"
264
+ :hide="['type', 'repeatCount']"
265
+ />
246
266
  <bind-anchor
247
267
  v-if="globalStore.handle_svg_info?.info.type === EDoneJsonType.ConnectionLine"
248
268
  v-model="globalStore.handle_svg_info!.info!.bind_anchors!.start"
@@ -173,12 +173,30 @@
173
173
  </div>
174
174
  <div class="el-divider el-divider--horizontal" role="separator" style="--el-border-style: solid"></div>
175
175
  <div class="font-bold mb-10px text-15px guide-title">横线和竖线</div>
176
- <div>画线的时候按住ctrl即可画竖线,按住shift即可画横线</div>
176
+ <div class="guide-text"
177
+ ><p>
178
+ 点击编辑器顶部连线按钮会进入连线状态,该状态下在画板点击鼠标左键即可开始画线,移动并再次点击左键创建新的节点,右键结束画线并退出连线状态;</p
179
+ >
180
+ <p>画线的时候按住ctrl即可画竖线,按住shift即可画横线</p></div
181
+ >
182
+ <div class="el-divider el-divider--horizontal" role="separator" style="--el-border-style: solid"></div>
183
+ <div class="font-bold mb-10px text-15px guide-title">绑定锚点</div>
184
+ <div class="guide-text">
185
+ <p
186
+ >组件在未选中时,鼠标经过组件时会出现锚点,鼠标悬浮在锚点上时,会有交互样式,点击左键即可以锚点为起点创建连线;</p
187
+ >
188
+ <p>同样,在连线时鼠标经过锚点时,会出现锚点交互样式,点击左键即可以锚点为连线终点结束连线;</p>
189
+ <p>这两种情况下的连线会绑定组件上的锚点,如需解绑,参考下面的‘锚点解绑’;</p>
190
+ <p>同样,也可先画线,再选中连线绑定想要绑定的组件锚点(连线只有首尾节点可以绑定锚点)</p>
191
+ </div>
177
192
  <div class="el-divider el-divider--horizontal" role="separator" style="--el-border-style: solid"></div>
178
193
  <div class="font-bold mb-10px text-15px guide-title">线段选中</div>
179
- <div style="padding-bottom: 14px">
180
- 若线段绑定了锚点,移动线段,绑定的锚点不会移动。若是想将线段整体移动,需要先选中线段,在右侧‘数据’栏里解除绑定
194
+ <div>
195
+ 若线段绑定了锚点,移动线段,绑定的锚点不会移动。若是想将线段整体移动,需要先解绑,参考下面的‘锚点解绑’
181
196
  </div>
197
+ <div class="el-divider el-divider--horizontal" role="separator" style="--el-border-style: solid"></div>
198
+ <div class="font-bold mb-10px text-15px guide-title">锚点解绑</div>
199
+ <div style="padding-bottom: 14px"> 选中线段,在右侧‘数据’栏里解除绑定;或者鼠标左键拖拽连线上需要解绑的节点</div>
182
200
  </el-scrollbar>
183
201
  </el-dialog>
184
202
  </template>
@@ -197,6 +215,12 @@
197
215
  .el-divider {
198
216
  border-color: #f1f1f5;
199
217
  }
218
+
219
+ .guide-text {
220
+ p {
221
+ line-height: 1.9;
222
+ }
223
+ }
200
224
  </style>
201
225
  <style lang="less">
202
226
  .guide-dialog {
@@ -80,7 +80,7 @@ interface IDoneJsonConfig {
80
80
  export interface IConfigItemState {
81
81
  [k: keyof any]: {
82
82
  title: string
83
- default: false
83
+ default: any
84
84
  props: { [key: string]: { openVal: any; closeVal: any } }
85
85
  }
86
86
  }
@@ -1,6 +1,6 @@
1
1
  import { config } from '@/config'
2
2
  import type { IConfigItem } from '@/config/types'
3
- import { isOfType, objectDeepClone, setSvgActualInfo } from '@/utils'
3
+ import { isOfType, objectDeepClone, setSvgActualInfo, unbindAnchors } from '@/utils'
4
4
  import { EGlobalStoreIntention, EMouseInfoState, EScaleInfoType } from './types'
5
5
  import type { IDoneJson, IGlobalStore, IMouseInfo, IScaleInfo } from './types'
6
6
  import { useHistoryRecord } from '@/hooks'
@@ -90,7 +90,9 @@ export const useGlobalStore = defineStore('global-store', {
90
90
  },
91
91
  spliceDoneJson(index: number) {
92
92
  const globalStore = useGlobalStore()
93
- globalStore.done_json.splice(index, 1)
93
+ const t = globalStore.done_json.splice(index, 1)
94
+ const item = t[0]
95
+ unbindAnchors(item.id)
94
96
  useHistoryRecord(globalStore.done_json)
95
97
  }
96
98
  }
@@ -286,15 +286,39 @@ export const moveAnchors = (done_json: IDoneJson) => {
286
286
  if (d.type === EDoneJsonType.ConnectionLine) {
287
287
  if (d.bind_anchors?.start?.target_id === done_json.id) {
288
288
  const a = getAnchorPosByAnchorType(d.bind_anchors.start.type, done_json)
289
- d.props.point_position.val[0] = { x: a.x - d.x, y: a.y - d.y }
289
+ d.props.point_position.val[0] = {
290
+ x: a.x - d.x,
291
+ y: a.y - d.y
292
+ }
290
293
  }
291
294
  if (d.bind_anchors?.end?.target_id === done_json.id) {
292
295
  const a = getAnchorPosByAnchorType(d.bind_anchors.end.type, done_json)
293
- d.props.point_position.val[d.props.point_position.val.length - 1] = { x: a.x - d.x, y: a.y - d.y }
296
+ d.props.point_position.val[d.props.point_position.val.length - 1] = {
297
+ x: a.x - d.x,
298
+ y: a.y - d.y
299
+ }
294
300
  }
295
301
  }
296
302
  }
297
303
  }
304
+ /**
305
+ * 解绑连线的锚点
306
+ * @param id 被绑定的组件的id
307
+ */
308
+ export const unbindAnchors = (id: string) => {
309
+ const globalStore = useGlobalStore(pinia)
310
+ for (let d of globalStore.done_json) {
311
+ if (d.type === EDoneJsonType.ConnectionLine) {
312
+ if (d.bind_anchors?.start?.target_id === id) {
313
+ d.bind_anchors.start = null
314
+ }
315
+ if (d.bind_anchors?.end?.target_id === id) {
316
+ d.bind_anchors.end = null
317
+ }
318
+ }
319
+ }
320
+ }
321
+
298
322
  /**
299
323
  * 根据锚点类型获取锚点坐标
300
324
  * @param anchor_type
@@ -464,7 +488,10 @@ export const createLine = (e: MouseEvent, type?: ELineBindAnchors, itemInfo?: ID
464
488
  width: 0,
465
489
  height: 0
466
490
  },
467
- center_position: { x: 0, y: 0 },
491
+ center_position: {
492
+ x: 0,
493
+ y: 0
494
+ },
468
495
  point_coordinate: {
469
496
  tl: {
470
497
  x: 0,