@zhangqingcq/vgce 0.0.24 → 0.0.26

Sign up to get free protection for your applications and to get access to all the features.
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,