Skip to content

Commit e3be22f

Browse files
XinyueDuduxinyue.dxy
andauthored
feat: add zoom in and out for graph (#173)
* feat: add zoom * feat: optimize icon * feat: add changeset * feat: optimize svg * fix: fixed ci error --------- Co-authored-by: duxinyue.dxy <[email protected]>
1 parent c91cac7 commit e3be22f

File tree

10 files changed

+181
-13
lines changed

10 files changed

+181
-13
lines changed

.changeset/yummy-months-return.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@antv/gpt-vis': patch
3+
---
4+
5+
add zoomin zoom out

src/ChartCodeRender/VisChart.tsx

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
import { CheckOutlined, CopyOutlined } from '@ant-design/icons';
21
import React, { memo, useRef, useState } from 'react';
32
import { ErrorBoundary } from 'react-error-boundary';
43
import { Light as SyntaxHighlighter } from 'react-syntax-highlighter';
54
import json from 'react-syntax-highlighter/dist/esm/languages/hljs/json';
65
import { magula } from 'react-syntax-highlighter/dist/esm/styles/hljs';
6+
import { Check, Copy, ZoomIn, ZoomOut } from './icon';
77
import Loading from './Loading';
88
import {
99
ChartWrapper,
10-
CopyButton,
1110
ErrorMessage,
1211
GlobalStyles,
1312
StyledGPTVis,
@@ -17,13 +16,23 @@ import {
1716
TabHeader,
1817
TabLeftGroup,
1918
TabRightGroup,
19+
TextButton,
2020
} from './styles';
2121
import type { ChartComponents, ChartJson, ComponentErrorRender, ErrorRender } from './type';
2222
import { handleCopyCode } from './utils';
2323

2424
// 注册 JSON 语言支持
2525
SyntaxHighlighter.registerLanguage('json', json);
2626

27+
const G6List = [
28+
'mind-map',
29+
'fishbone-diagram',
30+
'flow-diagram',
31+
'organization-chart',
32+
'network-graph',
33+
'indented-tree',
34+
];
35+
2736
type RenderVisChartProps = {
2837
content: string;
2938
components: ChartComponents;
@@ -42,6 +51,7 @@ export const RenderVisChart: React.FC<RenderVisChartProps> = memo(
4251
const [activeTab, setActiveTab] = useState<'chart' | 'code'>('chart');
4352
const [hasRenderError, setHasRenderError] = useState(false);
4453
const [copied, setCopied] = useState(false);
54+
const chartRef = useRef<any>(null);
4555
let chartJson: ChartJson;
4656

4757
try {
@@ -141,6 +151,25 @@ export const RenderVisChart: React.FC<RenderVisChartProps> = memo(
141151
}
142152
};
143153

154+
const isG6 = G6List.includes(type);
155+
156+
// 缩放功能函数
157+
const handleZoomOut = () => {
158+
if (chartRef.current && typeof chartRef.current.zoomTo === 'function') {
159+
const currentZoom = chartRef.current.getZoom() || 1;
160+
const newZoom = Math.min(currentZoom * 1.15, 1.5);
161+
chartRef.current.zoomTo(newZoom);
162+
}
163+
};
164+
165+
const handleZoomIn = () => {
166+
if (chartRef.current && typeof chartRef.current.zoomTo === 'function') {
167+
const currentZoom = chartRef.current.getZoom() || 1;
168+
const newZoom = Math.max(currentZoom / 1.15, 0.1);
169+
chartRef.current.zoomTo(newZoom);
170+
}
171+
};
172+
144173
// Render the supported chart component with data
145174
return (
146175
<TabContainer style={style}>
@@ -155,13 +184,32 @@ export const RenderVisChart: React.FC<RenderVisChartProps> = memo(
155184
</TabLeftGroup>
156185

157186
<TabRightGroup>
158-
{activeTab === 'code' && (
187+
{activeTab === 'chart' ? (
188+
<>
189+
{isG6 && (
190+
<>
191+
<TextButton
192+
onClick={handleZoomIn}
193+
style={{ width: '24px', height: '24px', padding: 0 }}
194+
>
195+
<ZoomIn size={18} />
196+
</TextButton>
197+
<TextButton
198+
onClick={handleZoomOut}
199+
style={{ width: '24px', height: '24px', padding: 0 }}
200+
>
201+
<ZoomOut size={18} />
202+
</TextButton>
203+
</>
204+
)}
205+
</>
206+
) : (
159207
<>
160208
{/* 复制代码 */}
161-
<CopyButton onClick={handleCopy}>
162-
{copied ? <CheckOutlined /> : <CopyOutlined />}
209+
<TextButton onClick={handleCopy}>
210+
{copied ? <Check /> : <Copy />}
163211
{copied ? '完成' : '复制'}
164-
</CopyButton>
212+
</TextButton>
165213
</>
166214
)}
167215
</TabRightGroup>
@@ -185,7 +233,12 @@ export const RenderVisChart: React.FC<RenderVisChartProps> = memo(
185233
<StyledGPTVis className="gpt-vis">
186234
<GlobalStyles />
187235
<ChartWrapper>
188-
<ChartComponent {...chartProps} />
236+
<ChartComponent
237+
{...chartProps}
238+
onReady={(chart: any) => {
239+
chartRef.current = chart;
240+
}}
241+
/>
189242
</ChartWrapper>
190243
</StyledGPTVis>
191244
</ErrorBoundary>

src/ChartCodeRender/icon.tsx

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import React from 'react';
2+
3+
interface Props extends React.SVGProps<SVGSVGElement> {
4+
size?: number;
5+
}
6+
7+
export const Copy: React.FC<Props> = ({ size = 14, fill = '#707070' }) => (
8+
<svg
9+
viewBox="0 0 1024 1024"
10+
version="1.1"
11+
xmlns="http://www.w3.org/2000/svg"
12+
p-id="5503"
13+
width={size}
14+
height={size}
15+
fill={fill}
16+
>
17+
<path
18+
d="M768 682.666667V170.666667a85.333333 85.333333 0 0 0-85.333333-85.333334H170.666667a85.333333 85.333333 0 0 0-85.333334 85.333334v512a85.333333 85.333333 0 0 0 85.333334 85.333333h512a85.333333 85.333333 0 0 0 85.333333-85.333333zM170.666667 170.666667h512v512H170.666667z m682.666666 85.333333v512a85.333333 85.333333 0 0 1-85.333333 85.333333H256a85.333333 85.333333 0 0 0 85.333333 85.333334h426.666667a170.666667 170.666667 0 0 0 170.666667-170.666667V341.333333a85.333333 85.333333 0 0 0-85.333334-85.333333z"
19+
p-id="5504"
20+
></path>
21+
</svg>
22+
);
23+
24+
export const ZoomOut: React.FC<Props> = ({ size = 14, fill = '#707070' }) => (
25+
<svg
26+
viewBox="0 0 1024 1024"
27+
version="1.1"
28+
xmlns="http://www.w3.org/2000/svg"
29+
p-id="5664"
30+
width={size}
31+
height={size}
32+
fill={fill}
33+
>
34+
<path
35+
d="M889.5 852.7l-220-219.9c45-53.4 72.1-122.3 72.1-197.5 0-169.4-137.8-307.3-307.3-307.3S127.1 265.8 127.1 435.3s137.8 307.3 307.3 307.3c76.1 0 145.7-27.8 199.4-73.8l219.8 219.8c4.9 5 11.4 7.4 17.9 7.4s13-2.5 17.9-7.4c10-9.9 10-26 0.1-35.9zM434.4 691.8c-141.4 0-256.5-115.1-256.5-256.5 0-141.5 115.1-256.5 256.5-256.5s256.5 115.1 256.5 256.5-115.1 256.5-256.5 256.5z"
36+
fill="#231815"
37+
p-id="5665"
38+
></path>
39+
<path
40+
d="M555 418.3h-99.8v-99.8c0-14-11.4-25.4-25.4-25.4s-25.4 11.4-25.4 25.4v99.8h-99.8c-14 0-25.4 11.4-25.4 25.4s11.4 25.4 25.4 25.4h99.8v99.8c0 14 11.4 25.4 25.4 25.4s25.4-11.4 25.4-25.4v-99.8H555c14 0 25.4-11.4 25.4-25.4S569 418.3 555 418.3z"
41+
fill="#231815"
42+
p-id="5666"
43+
></path>
44+
</svg>
45+
);
46+
47+
export const ZoomIn: React.FC<Props> = ({ size = 14, fill = '#707070' }) => (
48+
<svg
49+
viewBox="0 0 1024 1024"
50+
version="1.1"
51+
xmlns="http://www.w3.org/2000/svg"
52+
p-id="5826"
53+
width={size}
54+
height={size}
55+
fill={fill}
56+
>
57+
<path
58+
d="M889.5 852.7l-220-219.9c45-53.4 72.1-122.3 72.1-197.5 0-169.4-137.8-307.3-307.3-307.3S127.1 265.8 127.1 435.3s137.8 307.3 307.3 307.3c76.1 0 145.7-27.8 199.4-73.8l219.8 219.8c4.9 5 11.4 7.4 17.9 7.4s13-2.5 17.9-7.4c10-9.9 10-26 0.1-35.9zM434.4 691.8c-141.4 0-256.5-115.1-256.5-256.5 0-141.5 115.1-256.5 256.5-256.5s256.5 115.1 256.5 256.5-115.1 256.5-256.5 256.5z"
59+
fill="#231815"
60+
p-id="5827"
61+
></path>
62+
<path
63+
d="M555 418.3H304.7c-14 0-25.4 11.4-25.4 25.4s11.4 25.4 25.4 25.4H555c14 0 25.4-11.4 25.4-25.4S569 418.3 555 418.3z"
64+
fill="#231815"
65+
p-id="5828"
66+
></path>
67+
</svg>
68+
);
69+
70+
export const Check: React.FC<Props> = ({ size = 14, fill = '#707070' }) => (
71+
<svg
72+
viewBox="0 0 1024 1024"
73+
version="1.1"
74+
xmlns="http://www.w3.org/2000/svg"
75+
p-id="5988"
76+
width={size}
77+
height={size}
78+
fill={fill}
79+
>
80+
<path
81+
d="M380.416 822.144c-10.432 0-20.864-3.968-28.8-11.968L75.968 534.592c-15.936-15.936-15.936-41.664 0-57.6 15.872-15.872 41.664-15.872 57.536 0L380.416 723.84l510.08-510.016c15.872-15.936 41.664-15.936 57.536 0 15.936 15.936 15.936 41.664 0 57.6L409.216 810.24c-7.936 7.936-18.368 11.904-28.8 11.904z"
82+
fill=""
83+
p-id="5989"
84+
></path>
85+
</svg>
86+
);

src/ChartCodeRender/styles.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const StyledGPTVis = styled.div`
99
padding: 16px;
1010
`;
1111

12-
export const CopyButton = styled.button`
12+
export const TextButton = styled.button`
1313
border: none;
1414
box-shadow: none;
1515
background: transparent;
@@ -31,7 +31,7 @@ export const CopyButton = styled.button`
3131
&:hover,
3232
&:focus {
3333
color: #666;
34-
background: #f5f5f5;
34+
background: #e8e8e8;
3535
transform: scale(1.02);
3636
}
3737
@@ -171,3 +171,11 @@ export const StyledTabButton = styled.button<{ active?: boolean }>`
171171
transition: all 0.1s cubic-bezier(0.645, 0.045, 0.355, 1);
172172
}
173173
`;
174+
175+
export const Divider = styled.div`
176+
width: 1px;
177+
height: 16px;
178+
background-color: #d9d9d9;
179+
margin: 0 8px;
180+
flex-shrink: 0;
181+
`;

src/FishboneDiagram/index.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ export interface FishboneDiagramProps extends TreeGraphProps {}
1010
const defaultConfig: FishboneOptions = {
1111
autoFit: 'view',
1212
autoResize: true,
13+
zoomRange: [0.1, 5],
14+
zoom: 1,
15+
behaviors: ['drag-canvas'],
1316
};
1417

1518
const FishboneDiagram: React.FC<FishboneDiagramProps> = (props) => {

src/FlowDiagram/index.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ export interface FlowDiagramProps extends GraphProps {}
1414
const defaultConfig: FlowGraphOptions = {
1515
autoResize: true,
1616
autoFit: 'view',
17+
zoomRange: [0.1, 5],
18+
zoom: 1,
1719
node: {
1820
style: {
1921
component: (d: G6.NodeData) => {
@@ -49,8 +51,8 @@ const defaultConfig: FlowGraphOptions = {
4951
},
5052
},
5153
},
52-
behaviors: (prev) => [
53-
...prev,
54+
behaviors: [
55+
'drag-canvas',
5456
{
5557
type: 'hover-activate-neighbors',
5658
onHover: (e: G6.IPointerEvent) => {

src/IndentedTree/index.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ const defaultConfig: IndentedTreeOptions = {
1111
type: 'linear',
1212
autoFit: 'view',
1313
autoResize: true,
14+
zoomRange: [0.1, 5],
15+
zoom: 1,
1416
node: { animation: { update: false, translate: false } },
1517
edge: { animation: { update: false, translate: false } },
1618
transforms: (prev) => [
@@ -24,6 +26,7 @@ const defaultConfig: IndentedTreeOptions = {
2426
enable: true,
2527
},
2628
],
29+
behaviors: ['drag-canvas'],
2730
};
2831

2932
const IndentedTree: React.FC<IndentedTreeProps> = (props) => {

src/MindMap/index.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ const defaultConfig: MindMapOptions = {
1111
autoFit: 'view',
1212
autoResize: true,
1313
padding: 2,
14+
zoomRange: [0.1, 5],
15+
zoom: 1,
1416
node: { animation: { translate: false, update: false } },
1517
edge: { animation: { translate: false, update: false } },
1618
transforms: (prev) => [
@@ -24,6 +26,7 @@ const defaultConfig: MindMapOptions = {
2426
enable: true,
2527
},
2628
],
29+
behaviors: ['drag-canvas'],
2730
};
2831

2932
export interface MindMapProps extends TreeGraphProps {}

src/NetworkGraph/index.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ import { visGraphData2GraphData } from '../utils/graph';
88
export interface NetworkGraphProps extends GraphProps {}
99

1010
const defaultConfig: NetworkGraphOptions = {
11+
autoFit: 'view',
1112
autoResize: true,
13+
zoomRange: [0.1, 5],
14+
zoom: 1,
1215
node: {
1316
style: {
1417
size: 28,
@@ -27,7 +30,7 @@ const defaultConfig: NetworkGraphOptions = {
2730
},
2831
animation: { enter: false },
2932
},
30-
behaviors: (prev) => [...prev, { key: 'hover-activate', type: 'hover-activate', degree: 1 }],
33+
behaviors: ['drag-canvas', { key: 'hover-activate', type: 'hover-activate', degree: 1 }],
3134
transforms: (prev) => [...prev, 'process-parallel-edges'],
3235
layout: {
3336
type: 'force',

src/OrganizationChart/index.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ const defaultConfig: OrganizationChartOptions = {
1313
padding: [40, 0, 0, 120],
1414
autoFit: 'view',
1515
autoResize: true,
16+
zoomRange: [0.1, 5],
17+
zoom: 1,
1618
node: {
1719
style: {
1820
component: (d: G6.NodeData) => {
@@ -37,7 +39,7 @@ const defaultConfig: OrganizationChartOptions = {
3739
},
3840
},
3941
},
40-
behaviors: (prev) => [...prev, 'hover-activate-neighbors'],
42+
behaviors: ['drag-canvas', 'hover-activate-neighbors'],
4143
transforms: (prev) => [
4244
...prev.filter((t) => (t as G6.BaseTransformOptions).type !== 'collapse-expand-react-node'),
4345
{

0 commit comments

Comments
 (0)