@zhangqingcq/vgce 0.1.14 → 0.1.15
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +13 -3
- package/dist/style.css +1 -1
- package/dist/vgce.js +3545 -3491
- package/dist/vgce.umd.cjs +20 -20
- package/package.json +1 -1
- package/src/assets/base.less +32 -0
- package/src/components/svg-editor/center-panel.vue +17 -14
- package/src/components/svg-editor/right-panel.vue +2 -1
- package/src/components/svg-viewer.vue +74 -27
- package/src/components/vue3-ruler-tool.vue +9 -5
- package/src/config/types.ts +1 -0
- package/src/utils/index.ts +32 -14
- package/src/views/Preview.vue +1 -1
package/package.json
CHANGED
package/src/assets/base.less
CHANGED
@@ -109,7 +109,39 @@ body {
|
|
109
109
|
|
110
110
|
.tree-v {
|
111
111
|
--el-color-primary-light-9: @listActiveColor;
|
112
|
+
|
112
113
|
&.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content {
|
113
114
|
color: #fff;
|
114
115
|
}
|
115
116
|
}
|
117
|
+
|
118
|
+
.coverLayer {
|
119
|
+
position: absolute;
|
120
|
+
left: 0;
|
121
|
+
top: 0;
|
122
|
+
bottom: 0;
|
123
|
+
right: 0;
|
124
|
+
}
|
125
|
+
|
126
|
+
.can-not-select {
|
127
|
+
user-select: none;
|
128
|
+
}
|
129
|
+
|
130
|
+
.canvasInfoTxt {
|
131
|
+
color: #bbb;
|
132
|
+
position: absolute;
|
133
|
+
left: 20px;
|
134
|
+
bottom: 10px;
|
135
|
+
font-size: 12px;
|
136
|
+
|
137
|
+
.icoP {
|
138
|
+
margin-left: 10px;
|
139
|
+
position: relative;
|
140
|
+
top: 2px;
|
141
|
+
cursor: pointer;
|
142
|
+
|
143
|
+
&:hover {
|
144
|
+
color: @activeIconOut;
|
145
|
+
}
|
146
|
+
}
|
147
|
+
}
|
@@ -18,7 +18,8 @@
|
|
18
18
|
randomString,
|
19
19
|
resetHandlePointOld,
|
20
20
|
setSvgActualInfo,
|
21
|
-
|
21
|
+
getZoomPosition,
|
22
|
+
myFixed
|
22
23
|
} from '@/utils'
|
23
24
|
import {
|
24
25
|
calculateBottom,
|
@@ -494,10 +495,10 @@
|
|
494
495
|
//算出缩放倍数
|
495
496
|
if (globalStore.handle_svg_info && new_length.width > 0 && new_length.height > 0) {
|
496
497
|
const scale_x = !new_length.is_old_width
|
497
|
-
?
|
498
|
+
? myFixed(new_length.width / globalStore.handle_svg_info.info.actual_bound.width, 3)
|
498
499
|
: 1
|
499
500
|
const scale_y = !new_length.is_old_height
|
500
|
-
?
|
501
|
+
? myFixed(new_length.height / globalStore.handle_svg_info.info.actual_bound.height, 3)
|
501
502
|
: 1
|
502
503
|
const newCenterPoint = getCenterPoint(curPosition, globalStore.scale_info.symmetric_point)
|
503
504
|
if (
|
@@ -549,8 +550,9 @@
|
|
549
550
|
globalStore.handle_svg_info.info.x
|
550
551
|
) /
|
551
552
|
(Math.PI / 180)
|
552
|
-
globalStore.handle_svg_info.info.rotate =
|
553
|
-
|
553
|
+
globalStore.handle_svg_info.info.rotate = myFixed(
|
554
|
+
globalStore.rotate_info.angle + rotateDegreeAfter - rotateDegreeBefore,
|
555
|
+
2
|
554
556
|
)
|
555
557
|
} else if (globalStore.intention === EGlobalStoreIntention.Connection && globalStore.handle_svg_info) {
|
556
558
|
//鼠标移动的实时位置(相对于连线起始点,只在创建第一个点时记录了鼠标原始位置)
|
@@ -766,9 +768,11 @@
|
|
766
768
|
function onMousewheel(e: any) {
|
767
769
|
if (e?.wheelDelta) {
|
768
770
|
if (e.wheelDelta > 0) {
|
769
|
-
configStore.svg.scale =
|
770
|
-
|
771
|
-
|
771
|
+
configStore.svg.scale = myFixed(configStore.svg.scale + 0.1, 1)
|
772
|
+
getZoomPosition(e, configStore.svg.scale, svgEditLayoutStore.center_offset, true)
|
773
|
+
} else if (configStore.svg.scale > 0.1) {
|
774
|
+
configStore.svg.scale = myFixed(configStore.svg.scale - 0.1, 1)
|
775
|
+
getZoomPosition(e, configStore.svg.scale, svgEditLayoutStore.center_offset, false)
|
772
776
|
}
|
773
777
|
}
|
774
778
|
}
|
@@ -817,10 +821,10 @@
|
|
817
821
|
scale_y: number
|
818
822
|
) => {
|
819
823
|
return {
|
820
|
-
x:
|
821
|
-
y:
|
822
|
-
width:
|
823
|
-
height:
|
824
|
+
x: myFixed(actual_bound.x - (actual_bound.width / 2) * scale_x + actual_bound.width / 2, 1),
|
825
|
+
y: myFixed(actual_bound.y - (actual_bound.height / 2) * scale_y + actual_bound.height / 2, 1),
|
826
|
+
width: myFixed(actual_bound.width * scale_x, 1),
|
827
|
+
height: myFixed(actual_bound.height * scale_y, 1)
|
824
828
|
}
|
825
829
|
}
|
826
830
|
const onHandleKeyDown = (e: KeyboardEvent) => {
|
@@ -959,7 +963,7 @@
|
|
959
963
|
@mousewheel="onMousewheel"
|
960
964
|
>
|
961
965
|
<slot name="background" />
|
962
|
-
<div
|
966
|
+
<div class="coverLayer">
|
963
967
|
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
|
964
968
|
<defs>
|
965
969
|
<pattern id="pattern_grid" patternUnits="userSpaceOnUse" x="0" y="0" width="20" height="20">
|
@@ -980,7 +984,6 @@
|
|
980
984
|
:key="item.id"
|
981
985
|
:transform="`translate(${item.x},${item.y})rotate(0)scale(1)`"
|
982
986
|
v-show="item.display"
|
983
|
-
@mousewheel="stopEvent"
|
984
987
|
>
|
985
988
|
<g :class="`${getCommonClass(item)}`">
|
986
989
|
<g
|
@@ -313,7 +313,8 @@
|
|
313
313
|
<el-form-item label="行为" size="small">
|
314
314
|
<el-select v-model="item.action" @change="addEventList($event, item)">
|
315
315
|
<el-option value="ChangeAttr" label="改变属性" />
|
316
|
-
<el-option value="JavaScript" label="执行JavaScript" />
|
316
|
+
<el-option value="JavaScript" label="执行 JavaScript" />
|
317
|
+
<el-option value="Emit" label="emit 事件" />
|
317
318
|
</el-select>
|
318
319
|
</el-form-item>
|
319
320
|
|
@@ -1,11 +1,15 @@
|
|
1
1
|
<script setup lang="ts">
|
2
2
|
import { pinia } from '@/hooks'
|
3
|
+
import { ElIcon } from 'element-plus'
|
4
|
+
import { Aim } from '@element-plus/icons-vue'
|
3
5
|
import { useGlobalStore } from '@/stores/global'
|
4
6
|
import { EGlobalStoreIntention, EMouseInfoState } from '@/stores/global/types'
|
5
7
|
import type { IDoneJson } from '@/stores/global/types'
|
6
8
|
import {
|
7
9
|
componentsRegister,
|
8
10
|
getCommonClass,
|
11
|
+
getZoomPosition,
|
12
|
+
myFixed,
|
9
13
|
preventDefault,
|
10
14
|
prosToVBind,
|
11
15
|
setArrItemByID,
|
@@ -25,11 +29,12 @@
|
|
25
29
|
|
26
30
|
setEditorLoadTime()
|
27
31
|
|
28
|
-
const emit = defineEmits(['onMessage'])
|
32
|
+
const emit = defineEmits(['onMessage', 'onEvent'])
|
29
33
|
const props = withDefaults(
|
30
|
-
defineProps<{ vueComp?: Record<string, any>; data?: IDataModel; canvasDrag?: boolean }>(),
|
34
|
+
defineProps<{ vueComp?: Record<string, any>; data?: IDataModel; canvasDrag?: boolean; showCanvasInfo?: boolean }>(),
|
31
35
|
{
|
32
|
-
canvasDrag: true
|
36
|
+
canvasDrag: true,
|
37
|
+
showCanvasInfo: true
|
33
38
|
}
|
34
39
|
)
|
35
40
|
const globalStore = useGlobalStore(pinia)
|
@@ -72,14 +77,18 @@
|
|
72
77
|
return
|
73
78
|
}
|
74
79
|
const { clientX, clientY } = e
|
75
|
-
globalStore.mouse_info.new_position_x =
|
76
|
-
|
77
|
-
|
78
|
-
globalStore.mouse_info.
|
80
|
+
globalStore.mouse_info.new_position_x = Math.round(clientX / preview_data.config.svg.scale)
|
81
|
+
globalStore.mouse_info.new_position_y = Math.round(clientY / preview_data.config.svg.scale)
|
82
|
+
const x = Math.round(
|
83
|
+
globalStore.mouse_info.new_position_x - globalStore.mouse_info.position_x + globalStore.mouse_info.now_position_x
|
84
|
+
)
|
85
|
+
const y = Math.round(
|
86
|
+
globalStore.mouse_info.new_position_y - globalStore.mouse_info.position_y + globalStore.mouse_info.now_position_y
|
87
|
+
)
|
79
88
|
if (globalStore.intention == EGlobalStoreIntention.MoveCanvas) {
|
80
89
|
//移动画布
|
81
|
-
preview_data.layout_center.x =
|
82
|
-
preview_data.layout_center.y =
|
90
|
+
preview_data.layout_center.x = x
|
91
|
+
preview_data.layout_center.y = y
|
83
92
|
}
|
84
93
|
}
|
85
94
|
const onCanvasMouseUp = () => {
|
@@ -106,21 +115,23 @@
|
|
106
115
|
globalStore.intention = EGlobalStoreIntention.MoveCanvas
|
107
116
|
globalStore.mouse_info = {
|
108
117
|
state: EMouseInfoState.Down,
|
109
|
-
position_x: clientX,
|
110
|
-
position_y: clientY,
|
118
|
+
position_x: Math.round(clientX / preview_data.config.svg.scale),
|
119
|
+
position_y: Math.round(clientY / preview_data.config.svg.scale),
|
111
120
|
now_position_x: preview_data.layout_center.x,
|
112
121
|
now_position_y: preview_data.layout_center.y,
|
113
|
-
new_position_x:
|
114
|
-
new_position_y:
|
122
|
+
new_position_x: 0,
|
123
|
+
new_position_y: 0
|
115
124
|
}
|
116
125
|
}
|
117
126
|
|
118
127
|
function onMousewheel(e: any) {
|
119
128
|
if (e?.wheelDelta) {
|
120
129
|
if (e.wheelDelta > 0) {
|
121
|
-
preview_data.config.svg.scale =
|
130
|
+
preview_data.config.svg.scale = myFixed(preview_data.config.svg.scale + 0.1, 1)
|
131
|
+
getZoomPosition(e, preview_data.config.svg.scale, preview_data.layout_center, true)
|
122
132
|
} else {
|
123
|
-
preview_data.config.svg.scale =
|
133
|
+
preview_data.config.svg.scale = myFixed(preview_data.config.svg.scale - 0.1, 1)
|
134
|
+
getZoomPosition(e, preview_data.config.svg.scale, preview_data.layout_center, false)
|
124
135
|
}
|
125
136
|
}
|
126
137
|
}
|
@@ -156,7 +167,6 @@
|
|
156
167
|
return { cursor: t ? 'pointer' : 'default' }
|
157
168
|
}
|
158
169
|
const eventHandle = (root: IDoneJson, type: EEventType) => {
|
159
|
-
console.log(root.events, type)
|
160
170
|
if (root.events?.length > 0) {
|
161
171
|
for (let e of root.events) {
|
162
172
|
if (e.type === type) {
|
@@ -204,6 +214,28 @@
|
|
204
214
|
} else if (e.action === EEventAction.JavaScript) {
|
205
215
|
const t = new Function(e.scripts)
|
206
216
|
t()
|
217
|
+
} else if (e.action === EEventAction.Emit) {
|
218
|
+
const _k: Array<keyof IDoneJson> = [
|
219
|
+
'id',
|
220
|
+
'name',
|
221
|
+
'common_animations',
|
222
|
+
'display',
|
223
|
+
'props',
|
224
|
+
'title',
|
225
|
+
'type',
|
226
|
+
'x',
|
227
|
+
'y'
|
228
|
+
]
|
229
|
+
const _r: Record<string, any> = {}
|
230
|
+
_k.forEach((x) => {
|
231
|
+
if (root?.hasOwnProperty?.(x)) {
|
232
|
+
_r[x] = root[x]
|
233
|
+
}
|
234
|
+
})
|
235
|
+
emit('onEvent', {
|
236
|
+
event: e,
|
237
|
+
target: _r
|
238
|
+
})
|
207
239
|
}
|
208
240
|
}
|
209
241
|
}
|
@@ -230,6 +262,13 @@
|
|
230
262
|
}
|
231
263
|
}
|
232
264
|
|
265
|
+
const resetCanvas = () => {
|
266
|
+
preview_data.layout_center = {
|
267
|
+
x: 0,
|
268
|
+
y: 0
|
269
|
+
}
|
270
|
+
}
|
271
|
+
|
233
272
|
const connectNet = () => {
|
234
273
|
const m = preview_data.config.net.mqtt
|
235
274
|
if (m && m.url && m.user && m.pwd && m.topics) {
|
@@ -240,12 +279,12 @@
|
|
240
279
|
//用户拿到消息后可以配合setNodeAttrByID方法更新界面
|
241
280
|
//setNodeAttrByID的参数id可以在传给本组件的props.data(用户传进来的,自然知道值是多少)里done_json找到
|
242
281
|
/*如何找到指定组件的两种方案:
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
282
|
+
1.用你的项目里前后端约定的svg组件唯一标识符替换掉编辑器生成的id(必须保证唯一),然后调用setNodeAttrByID改变组件属性。
|
283
|
+
2.如果不想改动id(避免因不能保证手动改过的id唯一性导致编辑器功能异常),可以在config里给想要改变的组件的配置文件的props里增加一个字段,
|
284
|
+
如deviceCode(svg-text的配置文件里有被注释的例子),然后在编辑组态时,给对应组件填上对应的deviceCode(这样deviceCode就和组件id实现
|
285
|
+
了映射关系),并保存,后台给前台推MQTT消息时带上指定的deviceCode,前台预览时,在收到MQTT消息后,凭借消息里的deviceCode在done_json
|
286
|
+
找到组件的id(可以用vue的computed计算一份deviceCode和id的映射关系存到一个对象里,这样在需要id时可直接在计算出的对象凭借deviceCode
|
287
|
+
直接取到),即可用setNodeAttrByID改变组件属性*/
|
249
288
|
emit('onMessage', {
|
250
289
|
topics,
|
251
290
|
message
|
@@ -287,12 +326,12 @@
|
|
287
326
|
@contextmenu="preventDefault"
|
288
327
|
>
|
289
328
|
<slot name="background" />
|
290
|
-
<div
|
329
|
+
<div class="coverLayer">
|
291
330
|
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
|
292
331
|
<g
|
293
|
-
:transform="`translate(${preview_data.layout_center.x
|
294
|
-
preview_data.config.svg.scale
|
295
|
-
})`"
|
332
|
+
:transform="`translate(${preview_data.layout_center.x * preview_data.config.svg.scale},${
|
333
|
+
preview_data.layout_center.y * preview_data.config.svg.scale
|
334
|
+
})rotate(${0})scale(${preview_data.config.svg.scale})`"
|
296
335
|
>
|
297
336
|
<g
|
298
337
|
v-for="item in preview_data.done_json"
|
@@ -304,7 +343,6 @@
|
|
304
343
|
@mousedown="stopEvent"
|
305
344
|
@mousemove="stopEvent"
|
306
345
|
@mouseup="stopEvent"
|
307
|
-
@mousewheel="stopEvent"
|
308
346
|
>
|
309
347
|
<g :class="`${getCommonClass(item)}`">
|
310
348
|
<g
|
@@ -371,6 +409,15 @@
|
|
371
409
|
</g>
|
372
410
|
</svg>
|
373
411
|
</div>
|
412
|
+
|
413
|
+
<div class="can-not-select canvasInfoTxt" v-show="showCanvasInfo"
|
414
|
+
>缩放倍数:{{ preview_data.config.svg.scale }}倍,画布位置:{{ myFixed(preview_data.layout_center.x, 2) }},{{
|
415
|
+
myFixed(preview_data.layout_center.y, 2)
|
416
|
+
}}
|
417
|
+
<el-icon class="icoP" :size="14" @click="resetCanvas" title="重置位置">
|
418
|
+
<Aim />
|
419
|
+
</el-icon>
|
420
|
+
</div>
|
374
421
|
</div>
|
375
422
|
</template>
|
376
423
|
|
@@ -2,7 +2,7 @@
|
|
2
2
|
import { pinia } from '@/hooks'
|
3
3
|
import { useSvgEditLayoutStore } from '@/stores/svg-edit-layout'
|
4
4
|
import { useConfigStore } from '@/stores/config'
|
5
|
-
import {
|
5
|
+
import { myFixed, preventDefault } from '@/utils'
|
6
6
|
|
7
7
|
const emit = defineEmits(['onLineMouseUp'])
|
8
8
|
const props = withDefaults(
|
@@ -144,12 +144,12 @@
|
|
144
144
|
if (array.length === 0) {
|
145
145
|
for (let i = 0; i < length; i += props.stepLength) {
|
146
146
|
if (i % props.stepLength === 0) {
|
147
|
-
array.push({ id:
|
147
|
+
array.push({ id: myFixed(i / configStore.svg.scale - start, 0) })
|
148
148
|
}
|
149
149
|
}
|
150
150
|
} else {
|
151
151
|
array.forEach((e, i) => {
|
152
|
-
e.id =
|
152
|
+
e.id = myFixed((i * props.stepLength) / configStore.svg.scale - start, 0)
|
153
153
|
})
|
154
154
|
}
|
155
155
|
}
|
@@ -311,10 +311,14 @@
|
|
311
311
|
<span v-for="(item, index) in yScale" :style="{ top: index * stepLength + 'px' }" class="n">{{ item.id }}</span>
|
312
312
|
</div>
|
313
313
|
<div :style="{ top: verticalDottedTop + 'px' }" class="vue-ruler-ref-dot-h"
|
314
|
-
><span>{{
|
314
|
+
><span>{{
|
315
|
+
Math.round((verticalDottedTop - rulerHeight) / configStore.svg.scale - svgEditLayoutStore.center_offset.y)
|
316
|
+
}}</span></div
|
315
317
|
>
|
316
318
|
<div :style="{ left: horizontalDottedLeft + 'px' }" class="vue-ruler-ref-dot-v"
|
317
|
-
><span>{{
|
319
|
+
><span>{{
|
320
|
+
Math.round((horizontalDottedLeft - rulerWidth) / configStore.svg.scale - svgEditLayoutStore.center_offset.x)
|
321
|
+
}}</span></div
|
318
322
|
>
|
319
323
|
<div
|
320
324
|
v-for="item in lineList"
|
package/src/config/types.ts
CHANGED
package/src/utils/index.ts
CHANGED
@@ -18,6 +18,10 @@ export const preventDefault = (e: any) => {
|
|
18
18
|
e.preventDefault()
|
19
19
|
}
|
20
20
|
|
21
|
+
export const myFixed = (d: number, n: number) => {
|
22
|
+
return Number(d.toFixed(n))
|
23
|
+
}
|
24
|
+
|
21
25
|
export function componentsRegister(data?: Record<string, any>) {
|
22
26
|
//注册所有组件
|
23
27
|
const instance = getCurrentInstance()
|
@@ -95,19 +99,17 @@ export const calculateRotatedPointCoordinate = (
|
|
95
99
|
*/
|
96
100
|
|
97
101
|
return {
|
98
|
-
x:
|
99
|
-
(
|
100
|
-
(point.x - center.x) * Math.cos(angleToRadian(rotate)) -
|
102
|
+
x: myFixed(
|
103
|
+
(point.x - center.x) * Math.cos(angleToRadian(rotate)) -
|
101
104
|
(point.y - center.y) * Math.sin(angleToRadian(rotate)) +
|
102
|
-
center.x
|
103
|
-
|
105
|
+
center.x,
|
106
|
+
1
|
104
107
|
),
|
105
|
-
y:
|
106
|
-
(
|
107
|
-
(point.x - center.x) * Math.sin(angleToRadian(rotate)) +
|
108
|
+
y: myFixed(
|
109
|
+
(point.x - center.x) * Math.sin(angleToRadian(rotate)) +
|
108
110
|
(point.y - center.y) * Math.cos(angleToRadian(rotate)) +
|
109
|
-
center.y
|
110
|
-
|
111
|
+
center.y,
|
112
|
+
1
|
111
113
|
)
|
112
114
|
}
|
113
115
|
}
|
@@ -190,10 +192,10 @@ export const setSvgActualInfo = (done_json: IDoneJson, resize?: boolean) => {
|
|
190
192
|
}
|
191
193
|
} else {
|
192
194
|
const BBox = (queryBbox as SVGGraphicsElement).getBBox()
|
193
|
-
x =
|
194
|
-
y =
|
195
|
-
width =
|
196
|
-
height =
|
195
|
+
x = myFixed(BBox.x, 0)
|
196
|
+
y = myFixed(BBox.y, 0)
|
197
|
+
width = myFixed(BBox.width, 0)
|
198
|
+
height = myFixed(BBox.height, 0)
|
197
199
|
}
|
198
200
|
if (
|
199
201
|
rectBBox &&
|
@@ -568,3 +570,19 @@ export const createLine = (e: MouseEvent, type?: ELineBindAnchors, itemInfo?: ID
|
|
568
570
|
new_position_y: 0
|
569
571
|
}
|
570
572
|
}
|
573
|
+
|
574
|
+
export const getZoomPosition = (e: Record<string, any>, scale: any, center: Record<string, any>, isAdd: boolean) => {
|
575
|
+
/*鼠标位置*/
|
576
|
+
const offsetX = e.layerX
|
577
|
+
const offsetY = e.layerY
|
578
|
+
/*上次的画布位置*/
|
579
|
+
const tx = center.x
|
580
|
+
const ty = center.y
|
581
|
+
/*上次的scale*/
|
582
|
+
const ts = myFixed(isAdd ? scale - 0.1 : scale + 0.1, 1)
|
583
|
+
/*画布在没有缩放的时候移动位置*/
|
584
|
+
const lx = myFixed(tx + (offsetX * (ts - 1)) / ts, 1)
|
585
|
+
const ly = myFixed(ty + (offsetY * (ts - 1)) / ts, 1)
|
586
|
+
center.x = myFixed(lx / scale - ((offsetX - lx) * (scale - 1)) / scale, 2)
|
587
|
+
center.y = myFixed(ly / scale - ((offsetY - ly) * (scale - 1)) / scale, 2)
|
588
|
+
}
|
package/src/views/Preview.vue
CHANGED
@@ -15,7 +15,7 @@
|
|
15
15
|
<template>
|
16
16
|
<div class="previewPage">
|
17
17
|
<svg-viewer :data="store.data" />
|
18
|
-
<el-button @click="back" class="backBtn" :icon="ArrowLeftBold">返回</el-button>
|
18
|
+
<el-button type="text" @click="back" class="backBtn" :icon="ArrowLeftBold">返回</el-button>
|
19
19
|
</div>
|
20
20
|
</template>
|
21
21
|
|