hookehuyr

导出图片功能

...@@ -110,6 +110,11 @@ const router = createRouter({ ...@@ -110,6 +110,11 @@ const router = createRouter({
110 name: 'selection-select', 110 name: 'selection-select',
111 component: () => import('../views/selection-select/index.vue') 111 component: () => import('../views/selection-select/index.vue')
112 }, 112 },
113 + {
114 + path: '/snapshot',
115 + name: 'snapshot',
116 + component: () => import('../views/snapshot/index.vue')
117 + },
113 ] 118 ]
114 }) 119 })
115 120
......
1 <!-- 1 <!--
2 * @Date: 2025-03-10 14:37:31 2 * @Date: 2025-03-10 14:37:31
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2025-03-13 21:58:47 4 + * @LastEditTime: 2025-03-13 23:00:31
5 * @FilePath: /logic-flow2/src/views/home.vue 5 * @FilePath: /logic-flow2/src/views/home.vue
6 * @Description: 文件描述 6 * @Description: 文件描述
7 --> 7 -->
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
26 <el-button type="primary" @click="goTo('adv-dnd-panel-custom')">adv-dnd-panel-custom</el-button> 26 <el-button type="primary" @click="goTo('adv-dnd-panel-custom')">adv-dnd-panel-custom</el-button>
27 <el-button type="primary" @click="goTo('mini-map')">mini-map</el-button> 27 <el-button type="primary" @click="goTo('mini-map')">mini-map</el-button>
28 <el-button type="primary" @click="goTo('selection-select')">selection-select</el-button> 28 <el-button type="primary" @click="goTo('selection-select')">selection-select</el-button>
29 + <el-button type="primary" @click="goTo('snapshot')">snapshot</el-button>
29 </template> 30 </template>
30 31
31 <script setup> 32 <script setup>
......
1 +<!--
2 + * @Date: 2025-03-10 16:52:35
3 + * @LastEditors: hookehuyr hookehuyr@gmail.com
4 + * @LastEditTime: 2025-03-13 23:29:32
5 + * @FilePath: /logic-flow2/src/views/snapshot/index.vue
6 + * @Description: 导出图片,只能svg,其他类型效果太差
7 +-->
8 +<template>
9 + <div class="container">
10 + <div ref="container" class="flow-container"></div>
11 + <div class="control-panel">
12 + <el-input v-model="fileName" placeholder="文件名"></el-input>
13 + <el-select v-model="fileType">
14 + <el-option label="PNG" value="png" />
15 + <el-option label="JPEG" value="jpeg" />
16 + <el-option label="SVG" value="svg" />
17 + </el-select>
18 + <el-input-number v-model="width" placeholder="宽度" />
19 + <el-input-number v-model="height" placeholder="高度" />
20 + <el-color-picker v-model="backgroundColor" />
21 + <el-input-number v-model="padding" placeholder="内边距" />
22 + <el-input-number
23 + v-model="quality"
24 + :min="0"
25 + :max="1"
26 + :step="0.1"
27 + placeholder="图片质量"
28 + />
29 + <el-checkbox v-model="partial">局部渲染</el-checkbox>
30 +
31 + <el-button @click="downLoad">下载</el-button>
32 + <el-button @click="previewBlob">预览Blob</el-button>
33 + <el-button @click="previewBase64">预览Base64</el-button>
34 +
35 + <div v-if="blobData">
36 + <img :src="blobData" alt="blob preview" />
37 + </div>
38 + <div v-if="base64Data">
39 + <img :src="base64Data" alt="base64 preview" />
40 + </div>
41 + </div>
42 + </div>
43 +</template>
44 +
45 +<script setup>
46 +import LogicFlow from '@logicflow/core';
47 +import { Snapshot } from '@logicflow/extension';
48 +
49 +const container = ref(null);
50 +let lf = null;
51 +
52 +// 状态定义
53 +const fileName = ref('');
54 +const fileType = ref('png');
55 +const width = ref();
56 +const height = ref();
57 +const backgroundColor = ref('white');
58 +const padding = ref();
59 +const quality = ref();
60 +const partial = ref(false);
61 +const blobData = ref('');
62 +const base64Data = ref('');
63 +
64 +// 下载方法
65 +const downLoad = async () => {
66 + const params = {
67 + fileType: fileType.value,
68 + backgroundColor: backgroundColor.value,
69 + partial: partial.value,
70 + width: width.value,
71 + height: height.value,
72 + padding: padding.value,
73 + quality: quality.value,
74 + };
75 + console.log(params, 'params');
76 + await lf?.getSnapshot(fileName.value, params);
77 +};
78 +
79 +// 预览 blob
80 +const previewBlob = () => {
81 + if (lf) {
82 + base64Data.value = '';
83 + lf.getSnapshotBlob(backgroundColor.value, fileType.value)
84 + .then(({ data, width: w, height: h }) => {
85 + blobData.value = window.URL.createObjectURL(data);
86 + console.log('width, height ', w, h);
87 + });
88 + }
89 +};
90 +
91 +// 预览 base64
92 +const previewBase64 = () => {
93 + if (lf) {
94 + blobData.value = '';
95 + lf.getSnapshotBase64(backgroundColor.value)
96 + .then(({ data, width: w, height: h }) => {
97 + base64Data.value = data;
98 + console.log('width, height ', w, h);
99 + });
100 + }
101 +};
102 +
103 +onMounted(() => {
104 + lf = new LogicFlow({
105 + container: container.value,
106 + grid: true,
107 + plugins: [Snapshot],
108 + });
109 +
110 + lf.on('custom:button-click', (model) => {
111 + lf.setProperties(model.id, {
112 + body: 'LogicFlow',
113 + });
114 + });
115 +
116 + // 默认开启css样式
117 + const snapshot = lf.extension.snapshot;
118 + snapshot.useGlobalRules = true;
119 + snapshot.customCssRules = `
120 + .uml-wrapper {
121 + line-height: 1.2;
122 + text-align: center;
123 + color: blue;
124 + }
125 + `;
126 +
127 + lf.setTheme({
128 + rect: {
129 + fill: "#BDECFF",
130 + stroke: "#BDEC00",
131 + strokeWidth: 2,
132 + },
133 + });
134 +
135 + lf.render({
136 + nodes: [
137 + {
138 + id: 'node1',
139 + type: 'rect',
140 + x: 200,
141 + y: 100,
142 + },
143 + { id: 'node2', type: 'circle', x: 400, y: 100 },
144 + ],
145 + edges: [{ id: 'edge1', sourceNodeId: 'node1', targetNodeId: 'node2' }],
146 + });
147 + lf.translateCenter();
148 +});
149 +</script>
150 +
151 +<style scoped>
152 +.container {
153 + width: 100vw;
154 + height: 100vh;
155 + display: flex;
156 + flex-direction: column;
157 +}
158 +
159 +.flow-container {
160 + flex: 1;
161 + width: 100%;
162 + height: 100%;
163 +}
164 +
165 +.control-panel {
166 + position: absolute;
167 + top: 20px;
168 + left: 20px;
169 + display: flex;
170 + gap: 10px;
171 + flex-wrap: wrap;
172 + max-width: 80%;
173 + padding: 16px;
174 + background: white;
175 + border-radius: 4px;
176 + box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
177 +}
178 +
179 +.control-panel > * {
180 + min-width: 120px;
181 +}
182 +</style>