Skip to content

Commit 09c90be

Browse files
yiidotboyongjiong
authored andcommitted
feat(extension): 支持导出节点中的网络图片
1 parent 1d0d44e commit 09c90be

File tree

5 files changed

+420
-3
lines changed

5 files changed

+420
-3
lines changed

examples/feature-examples/.umirc.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,11 @@ export default defineConfig({
117117
name: 'MiniMap 插件',
118118
component: './extensions/mini-map',
119119
},
120+
{
121+
path: '/extension/snapshot',
122+
name: 'Snapshot 插件',
123+
component: './extensions/snapshot',
124+
},
120125
],
121126
},
122127
],
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { RectNode, RectNodeModel, h } from '@logicflow/core'
2+
3+
class ImageModel extends RectNodeModel {
4+
initNodeData(data: any) {
5+
super.initNodeData(data)
6+
this.width = 80
7+
this.height = 60
8+
}
9+
}
10+
11+
class ImageNode extends RectNode {
12+
getImageHref() {
13+
return 'https://dpubstatic.udache.com/static/dpubimg/0oqFX1nvbD/cloud.png'
14+
}
15+
getShape() {
16+
const { x, y, width, height } = this.props.model
17+
const href = this.getImageHref()
18+
const attrs = {
19+
x: x - (1 / 2) * width,
20+
y: y - (1 / 2) * height,
21+
width,
22+
height,
23+
href,
24+
// 根据宽高缩放
25+
preserveAspectRatio: 'none meet',
26+
}
27+
return h('g', {}, [h('image', { ...attrs })])
28+
}
29+
}
30+
31+
export default {
32+
type: 'image',
33+
view: ImageNode,
34+
model: ImageModel,
35+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.viewport {
2+
height: calc(100vh - 250px);
3+
overflow: hidden;
4+
}
5+
6+
.preview {
7+
width: 100%;
8+
}
Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
import LogicFlow from '@logicflow/core'
2+
import { Snapshot } from '@logicflow/extension'
3+
4+
import { Button, Card, Col, Divider, Flex, Row, Space } from 'antd'
5+
import { useEffect, useRef, useState } from 'react'
6+
import styles from './index.less'
7+
8+
import '@logicflow/core/es/index.css'
9+
import '@logicflow/extension/es/index.css'
10+
import ImageNode from './ImageNode'
11+
12+
const config: Partial<LogicFlow.Options> = {
13+
isSilentMode: false,
14+
stopScrollGraph: false,
15+
stopZoomGraph: false,
16+
stopMoveGraph: true,
17+
style: {
18+
rect: {
19+
rx: 5,
20+
ry: 5,
21+
strokeWidth: 2,
22+
},
23+
circle: {
24+
fill: '#f5f5f5',
25+
stroke: '#666',
26+
},
27+
ellipse: {
28+
fill: '#dae8fc',
29+
stroke: '#6c8ebf',
30+
},
31+
polygon: {
32+
fill: '#d5e8d4',
33+
stroke: '#82b366',
34+
},
35+
diamond: {
36+
fill: '#ffe6cc',
37+
stroke: '#d79b00',
38+
},
39+
text: {
40+
color: '#b85450',
41+
fontSize: 12,
42+
},
43+
},
44+
}
45+
46+
const data = {
47+
nodes: [
48+
{
49+
id: '1',
50+
type: 'rect',
51+
x: 150,
52+
y: 100,
53+
text: '矩形',
54+
},
55+
{
56+
id: '2',
57+
type: 'circle',
58+
x: 350,
59+
y: 100,
60+
text: '圆形',
61+
},
62+
{
63+
id: '3',
64+
type: 'image',
65+
x: 550,
66+
y: 100,
67+
text: '云',
68+
},
69+
{
70+
id: '4',
71+
type: 'polygon',
72+
x: 150,
73+
y: 250,
74+
text: '多边形',
75+
},
76+
{
77+
id: '5',
78+
type: 'image',
79+
x: 350,
80+
y: 250,
81+
text: '菱形',
82+
},
83+
{
84+
id: '6',
85+
type: 'text',
86+
x: 550,
87+
y: 250,
88+
text: '纯文本节点',
89+
},
90+
{
91+
id: '7',
92+
type: 'html',
93+
x: 150,
94+
y: 400,
95+
text: 'html节点',
96+
},
97+
],
98+
edges: [
99+
{
100+
id: 'e_1',
101+
type: 'polyline',
102+
sourceNodeId: '1',
103+
targetNodeId: '2',
104+
},
105+
{
106+
id: 'e_2',
107+
type: 'polyline',
108+
sourceNodeId: '2',
109+
targetNodeId: '3',
110+
},
111+
{
112+
id: 'e_3',
113+
type: 'polyline',
114+
sourceNodeId: '4',
115+
targetNodeId: '5',
116+
},
117+
],
118+
}
119+
120+
/**
121+
* 框选插件 Snapshot 示例
122+
*/
123+
export default function SnapshotExample() {
124+
const lfRef = useRef<LogicFlow>()
125+
const containerRef = useRef<HTMLDivElement>(null)
126+
const [blobData, setBlobData] = useState('')
127+
const [base64Data, setBase64Data] = useState('')
128+
129+
// 初始化 LogicFlow
130+
useEffect(() => {
131+
if (!lfRef.current) {
132+
const lf = new LogicFlow({
133+
...config,
134+
container: containerRef.current!,
135+
grid: {
136+
size: 20,
137+
},
138+
plugins: [Snapshot as any],
139+
})
140+
lf.register(ImageNode)
141+
142+
lf.on(
143+
'selection:selected-area',
144+
({ topLeft, bottomRight }: Record<string, LogicFlow.PointTuple>) => {
145+
console.log('get selection area:', topLeft, bottomRight)
146+
},
147+
)
148+
lf.render(data)
149+
lfRef.current = lf
150+
}
151+
}, [])
152+
153+
const handleGetSnapshot = () => {
154+
if (lfRef.current) {
155+
lfRef.current.getSnapshot()
156+
}
157+
}
158+
159+
const handlePreviewSnapshotBlob = () => {
160+
if (lfRef.current) {
161+
setBase64Data('')
162+
lfRef.current
163+
.getSnapshotBlob('#FFFFFF')
164+
.then(
165+
({
166+
data,
167+
width,
168+
height,
169+
}: {
170+
data: Blob
171+
width: number
172+
height: number
173+
}) => {
174+
setBlobData(window.URL.createObjectURL(data))
175+
console.log('width, height ', width, height)
176+
},
177+
)
178+
}
179+
}
180+
181+
const handlePreviewSnapshotBase64 = () => {
182+
if (lfRef.current) {
183+
setBlobData('')
184+
lfRef.current
185+
.getSnapshotBase64('#FFFFFF')
186+
.then(
187+
({
188+
data,
189+
width,
190+
height,
191+
}: {
192+
data: string
193+
width: number
194+
height: number
195+
}) => {
196+
setBase64Data(data)
197+
console.log('width, height ', width, height)
198+
},
199+
)
200+
}
201+
}
202+
203+
return (
204+
<Card title="LogicFlow Extension - Snapshot">
205+
<Flex wrap="wrap" gap="middle" align="center" justify="space-between">
206+
<Space>
207+
<Button onClick={handleGetSnapshot}>下载快照</Button>
208+
<Button onClick={handlePreviewSnapshotBlob}>预览(blob)</Button>
209+
<Button onClick={handlePreviewSnapshotBase64}>预览(base64)</Button>
210+
</Space>
211+
</Flex>
212+
<Divider />
213+
<Row>
214+
<Col span={12}>
215+
<div ref={containerRef} id="graph" className={styles.viewport}></div>
216+
</Col>
217+
<Col span={12}>
218+
{blobData && (
219+
<>
220+
<h2>blobData</h2>
221+
<img key="blob" src={blobData} className={styles.preview} />
222+
</>
223+
)}
224+
{base64Data && (
225+
<>
226+
<h2>base64Data</h2>
227+
<img key="base64" src={base64Data} className={styles.preview} />
228+
</>
229+
)}
230+
</Col>
231+
</Row>
232+
</Card>
233+
)
234+
}

0 commit comments

Comments
 (0)