@fe-free/core 2.3.3 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/package.json +2 -2
- package/src/index.ts +2 -0
- package/src/infinite_list/index.tsx +121 -0
- package/src/infinite_list/infinite_list.stories.tsx +47 -0
- package/src/markdown/code.tsx +6 -0
- package/src/markdown/hm_chart.tsx +176 -0
- package/src/markdown/markdown.stories.tsx +177 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @fe-free/core
|
|
2
2
|
|
|
3
|
+
## 2.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- feat: add InfiniteList and sleep
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies
|
|
12
|
+
- @fe-free/tool@2.4.0
|
|
13
|
+
|
|
14
|
+
## 2.3.4
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- feat: markdown chart
|
|
19
|
+
- @fe-free/tool@2.3.4
|
|
20
|
+
|
|
3
21
|
## 2.3.3
|
|
4
22
|
|
|
5
23
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fe-free/core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"author": "",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"remark-gfm": "^4.0.1",
|
|
42
42
|
"vanilla-jsoneditor": "^0.23.1",
|
|
43
43
|
"zustand": "^4.5.4",
|
|
44
|
-
"@fe-free/tool": "2.
|
|
44
|
+
"@fe-free/tool": "2.4.0"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"@ant-design/pro-components": "2.8.9",
|
package/src/index.ts
CHANGED
|
@@ -33,6 +33,8 @@ export {
|
|
|
33
33
|
} from './form';
|
|
34
34
|
export { RequestError, initErrorHandle } from './global/error';
|
|
35
35
|
export { downloadInterceptor } from './global/interceptors';
|
|
36
|
+
export { InfiniteList } from './infinite_list';
|
|
37
|
+
export type { InfiniteListProps } from './infinite_list';
|
|
36
38
|
export { Markdown } from './markdown';
|
|
37
39
|
export { PageLayout } from './page_layout';
|
|
38
40
|
export { routeTool } from './route';
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { Spin } from 'antd';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
import type { ReactNode } from 'react';
|
|
4
|
+
import { useImperativeHandle, useRef, useState } from 'react';
|
|
5
|
+
import { useGlobalInfiniteScroll } from '../ahooks/use_global_infinite_scroll';
|
|
6
|
+
|
|
7
|
+
interface InfiniteListProps<D, P> {
|
|
8
|
+
request: (params: { current: number; pageSize: number } & P) => Promise<{
|
|
9
|
+
data: D[];
|
|
10
|
+
total: number;
|
|
11
|
+
}>;
|
|
12
|
+
renderItem: ({ item, index }: { item: D; index: number }) => ReactNode;
|
|
13
|
+
params?: P;
|
|
14
|
+
/** 每页数量 */
|
|
15
|
+
pageSize: number;
|
|
16
|
+
/** 定义网格布局 */
|
|
17
|
+
gridClassName: string;
|
|
18
|
+
className?: string;
|
|
19
|
+
actionRef?: React.RefObject<{ reload: () => void }>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const emptyParams = {};
|
|
23
|
+
|
|
24
|
+
const InfiniteListBase = <D, P>({
|
|
25
|
+
request,
|
|
26
|
+
renderItem,
|
|
27
|
+
params = emptyParams as P,
|
|
28
|
+
actionRef,
|
|
29
|
+
pageSize,
|
|
30
|
+
gridClassName,
|
|
31
|
+
className,
|
|
32
|
+
}: InfiniteListProps<D, P>) => {
|
|
33
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
34
|
+
|
|
35
|
+
const { data, loading, loadingMore, noMore, mutate, reload } = useGlobalInfiniteScroll(
|
|
36
|
+
async (p) => {
|
|
37
|
+
// 获得当前页面
|
|
38
|
+
const current = p?.nextId || 1;
|
|
39
|
+
|
|
40
|
+
const res = await request({
|
|
41
|
+
current,
|
|
42
|
+
pageSize,
|
|
43
|
+
...params,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
let hasMore = true;
|
|
47
|
+
// 总数少于当前页数 * 每页数量,则没有更多
|
|
48
|
+
if (res.total <= current * pageSize) {
|
|
49
|
+
hasMore = false;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
list: res.data,
|
|
54
|
+
nextId: hasMore ? current + 1 : undefined,
|
|
55
|
+
};
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
target: ref,
|
|
59
|
+
isNoMore: (d) => d?.nextId === undefined,
|
|
60
|
+
},
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
useImperativeHandle(actionRef, () => ({
|
|
64
|
+
reload: async () => {
|
|
65
|
+
// 没有数据,相当于重新获取
|
|
66
|
+
if (!data) {
|
|
67
|
+
return reload();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// 获取全部数据。因为不清楚哪个要更新。
|
|
71
|
+
const res = await request({
|
|
72
|
+
...params,
|
|
73
|
+
current: 1,
|
|
74
|
+
pageSize,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// 只更新数据
|
|
78
|
+
data.list = res.data;
|
|
79
|
+
|
|
80
|
+
mutate({
|
|
81
|
+
...data,
|
|
82
|
+
});
|
|
83
|
+
},
|
|
84
|
+
}));
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<div ref={ref} className={classNames('h-full overflow-y-auto', className)}>
|
|
88
|
+
{loading && (
|
|
89
|
+
<div className="flex h-full w-full items-center justify-center">
|
|
90
|
+
<Spin />
|
|
91
|
+
</div>
|
|
92
|
+
)}
|
|
93
|
+
{!loading && (
|
|
94
|
+
<div className={classNames('grid', gridClassName)}>
|
|
95
|
+
{data?.list?.map((item, index) => {
|
|
96
|
+
return <div key={index}>{renderItem({ item, index })}</div>;
|
|
97
|
+
})}
|
|
98
|
+
</div>
|
|
99
|
+
)}
|
|
100
|
+
<div className="flex w-full items-center justify-center">
|
|
101
|
+
{noMore && <div className="my-5 text-center text-desc">没有更多数据</div>}
|
|
102
|
+
{loadingMore && <div className="my-5 text-center text-desc">加载更多数据中...</div>}
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
function InfiniteList<D, P>(props: InfiniteListProps<D, P>) {
|
|
109
|
+
const [reloadCount, setReloadCount] = useState(0);
|
|
110
|
+
|
|
111
|
+
useImperativeHandle(props.actionRef, () => ({
|
|
112
|
+
reload: () => {
|
|
113
|
+
setReloadCount((prev) => prev + 1);
|
|
114
|
+
},
|
|
115
|
+
}));
|
|
116
|
+
|
|
117
|
+
return <InfiniteListBase key={reloadCount} {...props} />;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export { InfiniteList };
|
|
121
|
+
export type { InfiniteListProps };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { InfiniteList } from '@fe-free/core';
|
|
2
|
+
import { sleep } from '@fe-free/tool';
|
|
3
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof InfiniteList> = {
|
|
6
|
+
title: '@fe-free/core/InfiniteList',
|
|
7
|
+
component: InfiniteList,
|
|
8
|
+
tags: ['autodocs'],
|
|
9
|
+
parameters: {
|
|
10
|
+
docs: {
|
|
11
|
+
description: {
|
|
12
|
+
component: '无线滚动列表',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export default meta;
|
|
19
|
+
|
|
20
|
+
type Story = StoryObj<typeof InfiniteList>;
|
|
21
|
+
|
|
22
|
+
export const Resolve: Story = {
|
|
23
|
+
render: () => {
|
|
24
|
+
return (
|
|
25
|
+
<div className="h-[500px]">
|
|
26
|
+
<InfiniteList
|
|
27
|
+
request={async ({ current, pageSize }) => {
|
|
28
|
+
await sleep(500);
|
|
29
|
+
return {
|
|
30
|
+
data: new Array(pageSize).fill(0).map((_, index) => index + (current - 1) * pageSize),
|
|
31
|
+
total: 100,
|
|
32
|
+
};
|
|
33
|
+
}}
|
|
34
|
+
renderItem={({ item }) => {
|
|
35
|
+
return (
|
|
36
|
+
<div className="p-2">
|
|
37
|
+
<div className="h-[100px] bg-red-500">item{item}</div>
|
|
38
|
+
</div>
|
|
39
|
+
);
|
|
40
|
+
}}
|
|
41
|
+
pageSize={20}
|
|
42
|
+
gridClassName="grid-cols-3"
|
|
43
|
+
/>
|
|
44
|
+
</div>
|
|
45
|
+
);
|
|
46
|
+
},
|
|
47
|
+
};
|
package/src/markdown/code.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
|
|
2
2
|
import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism';
|
|
3
3
|
import { ChartBlock } from './chart';
|
|
4
|
+
import { HMChartBlock } from './hm_chart';
|
|
4
5
|
|
|
5
6
|
function CodeBlock(props: any) {
|
|
6
7
|
const { children, className, ...rest } = props;
|
|
@@ -11,6 +12,11 @@ function CodeBlock(props: any) {
|
|
|
11
12
|
return <ChartBlock>{children}</ChartBlock>;
|
|
12
13
|
}
|
|
13
14
|
|
|
15
|
+
// 如果是 hmchart 类型的代码块,使用 HMChartBlock 组件
|
|
16
|
+
if (match && match[1] === 'hmchart') {
|
|
17
|
+
return <HMChartBlock>{children}</HMChartBlock>;
|
|
18
|
+
}
|
|
19
|
+
|
|
14
20
|
return (
|
|
15
21
|
<div className="markdown-body-code-block">
|
|
16
22
|
{match ? (
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { Column, Line, Pie, Scatter } from '@ant-design/plots';
|
|
2
|
+
import React, { useMemo } from 'react';
|
|
3
|
+
|
|
4
|
+
enum EnumType {
|
|
5
|
+
/** 折线图 */
|
|
6
|
+
LINE = 'line',
|
|
7
|
+
/** 柱状图 */
|
|
8
|
+
BAR = 'bar',
|
|
9
|
+
/** 饼图 */
|
|
10
|
+
PIE = 'pie',
|
|
11
|
+
/** 散点图 */
|
|
12
|
+
SCATTER = 'scatter',
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface HMChartConfigLine<D> {
|
|
16
|
+
/** 折线图 */
|
|
17
|
+
type: EnumType.LINE;
|
|
18
|
+
/** 标题 */
|
|
19
|
+
title?: string;
|
|
20
|
+
/** 就是纯粹的数据 */
|
|
21
|
+
data: D[];
|
|
22
|
+
/** 横坐标字段 */
|
|
23
|
+
xField: keyof D;
|
|
24
|
+
/** 纵坐标字段 */
|
|
25
|
+
yField: keyof D;
|
|
26
|
+
/** 系列字段,多折线图用 */
|
|
27
|
+
seriesField?: keyof D;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface HMChartConfigBar<D> {
|
|
31
|
+
/** 柱状图 */
|
|
32
|
+
type: EnumType.BAR;
|
|
33
|
+
/** 标题 */
|
|
34
|
+
title?: string;
|
|
35
|
+
/** 就是纯粹的数据 */
|
|
36
|
+
data: D[];
|
|
37
|
+
/** 横坐标字段 */
|
|
38
|
+
xField: keyof D;
|
|
39
|
+
/** 纵坐标字段 */
|
|
40
|
+
yField: keyof D;
|
|
41
|
+
/** 系列字段,多折线图用 */
|
|
42
|
+
seriesField?: keyof D;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
interface HMChartConfigPie<D> {
|
|
46
|
+
/** 饼图 */
|
|
47
|
+
type: EnumType.PIE;
|
|
48
|
+
/** 标题 */
|
|
49
|
+
title?: string;
|
|
50
|
+
/** 就是纯粹的数据 */
|
|
51
|
+
data: D[];
|
|
52
|
+
/** 角度字段 */
|
|
53
|
+
angleField: keyof D;
|
|
54
|
+
/** 颜色字段 */
|
|
55
|
+
colorField: keyof D;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
interface HMChartConfigScatter<D> {
|
|
59
|
+
/** 散点图 */
|
|
60
|
+
type: EnumType.SCATTER;
|
|
61
|
+
/** 标题 */
|
|
62
|
+
title?: string;
|
|
63
|
+
/** 就是纯粹的数据 */
|
|
64
|
+
data: D[];
|
|
65
|
+
/** 横坐标字段 */
|
|
66
|
+
xField: keyof D;
|
|
67
|
+
/** 纵坐标字段 */
|
|
68
|
+
yField: keyof D;
|
|
69
|
+
/** 颜色字段 */
|
|
70
|
+
colorField?: keyof D;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
type HMChartConfig<D> =
|
|
74
|
+
| HMChartConfigLine<D>
|
|
75
|
+
| HMChartConfigBar<D>
|
|
76
|
+
| HMChartConfigPie<D>
|
|
77
|
+
| HMChartConfigScatter<D>;
|
|
78
|
+
|
|
79
|
+
// 错误处理组件
|
|
80
|
+
function ChartError(props: { children?: React.ReactNode }) {
|
|
81
|
+
const { children } = props;
|
|
82
|
+
return (
|
|
83
|
+
<div className="markdown-body-hmchart-block">
|
|
84
|
+
<div style={{ textAlign: 'center', padding: '20px' }}>{children || '图表发生错误'}</div>
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
class ErrorBoundary extends React.Component {
|
|
90
|
+
state = { hasError: false };
|
|
91
|
+
|
|
92
|
+
static getDerivedStateFromError(error) {
|
|
93
|
+
console.error('ErrorBoundary:', error);
|
|
94
|
+
return { hasError: true };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
componentDidCatch(error, info) {
|
|
98
|
+
console.error('Error caught:', error, info);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
render() {
|
|
102
|
+
if (this.state.hasError) {
|
|
103
|
+
return <ChartError />;
|
|
104
|
+
}
|
|
105
|
+
return this.props.children;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function ChartOfLine(props: { config: HMChartConfigLine<any> }) {
|
|
110
|
+
return <Line colorField={props.config.seriesField} {...props.config} />;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function ChartOfBar(props: { config: HMChartConfigBar<any> }) {
|
|
114
|
+
return <Column colorField={props.config.seriesField} {...props.config} />;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function ChartOfPie(props: { config: HMChartConfigPie<any> }) {
|
|
118
|
+
return <Pie {...props.config} />;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function ChartOfScatter(props: { config: HMChartConfigScatter<any> }) {
|
|
122
|
+
return <Scatter {...props.config} />;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// 主 ChartBlock 组件
|
|
126
|
+
function HMChartBlockBase(props: any) {
|
|
127
|
+
const { children } = props;
|
|
128
|
+
|
|
129
|
+
const chartConfig = useMemo(() => {
|
|
130
|
+
try {
|
|
131
|
+
return JSON.parse(children);
|
|
132
|
+
} catch (error) {
|
|
133
|
+
console.error('Failed to parse chart data:', error);
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
}, [children]);
|
|
137
|
+
|
|
138
|
+
if (!chartConfig) {
|
|
139
|
+
return <ChartError />;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const { type, ...config } = chartConfig;
|
|
143
|
+
|
|
144
|
+
switch (type) {
|
|
145
|
+
case EnumType.LINE:
|
|
146
|
+
return <ChartOfLine config={config} />;
|
|
147
|
+
|
|
148
|
+
case EnumType.BAR:
|
|
149
|
+
return <ChartOfBar config={config} />;
|
|
150
|
+
|
|
151
|
+
case EnumType.PIE:
|
|
152
|
+
return <ChartOfPie config={config} />;
|
|
153
|
+
|
|
154
|
+
case EnumType.SCATTER:
|
|
155
|
+
return <ChartOfScatter config={config} />;
|
|
156
|
+
|
|
157
|
+
default:
|
|
158
|
+
return <ChartError>不支持的图表类型:{type}</ChartError>;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function HMChartBlock(props: any) {
|
|
163
|
+
const { children } = props;
|
|
164
|
+
|
|
165
|
+
// eslint-disable-next-line no-irregular-whitespace
|
|
166
|
+
const content = children?.replace(/ /g, '');
|
|
167
|
+
|
|
168
|
+
return (
|
|
169
|
+
<ErrorBoundary>
|
|
170
|
+
<HMChartBlockBase>{content}</HMChartBlockBase>
|
|
171
|
+
</ErrorBoundary>
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export { HMChartBlock };
|
|
176
|
+
export type { HMChartConfig };
|
|
@@ -141,8 +141,7 @@ export const DeepSeekPending: Story = {
|
|
|
141
141
|
|
|
142
142
|
export const Chart: Story = {
|
|
143
143
|
args: {
|
|
144
|
-
children:
|
|
145
|
-
|
|
144
|
+
children: `
|
|
146
145
|
## 折线图示例
|
|
147
146
|
|
|
148
147
|
\`\`\`chart
|
|
@@ -320,3 +319,179 @@ export const Chart: Story = {
|
|
|
320
319
|
`,
|
|
321
320
|
},
|
|
322
321
|
};
|
|
322
|
+
|
|
323
|
+
export const HMChart: Story = {
|
|
324
|
+
args: {
|
|
325
|
+
children: `
|
|
326
|
+
类型定义见:https://github.com/frontend-free/free/blob/main/packages/core/src/markdown/hm_chart.tsx
|
|
327
|
+
|
|
328
|
+
## 折线图示例
|
|
329
|
+
|
|
330
|
+
\`\`\`hmchart
|
|
331
|
+
{
|
|
332
|
+
"title": "趋势变化",
|
|
333
|
+
"type": "line",
|
|
334
|
+
"data": [
|
|
335
|
+
{ "year": "1991", "value": 3 },
|
|
336
|
+
{ "year": "1992", "value": 4 },
|
|
337
|
+
{ "year": "1993", "value": 3.5 }
|
|
338
|
+
],
|
|
339
|
+
"xField": "year",
|
|
340
|
+
"yField": "value"
|
|
341
|
+
}
|
|
342
|
+
\`\`\`
|
|
343
|
+
|
|
344
|
+
\`\`\`hmchart
|
|
345
|
+
{
|
|
346
|
+
"title": "多条趋势变化",
|
|
347
|
+
"type": "line",
|
|
348
|
+
"data": [
|
|
349
|
+
{ "year": "1991", "type": "A", "value": 3 },
|
|
350
|
+
{ "year": "1991", "type": "B", "value": 4 },
|
|
351
|
+
{ "year": "1992", "type": "A", "value": 4 },
|
|
352
|
+
{ "year": "1992", "type": "B", "value": 4.5 },
|
|
353
|
+
{ "year": "1993", "type": "A", "value": 3.5 },
|
|
354
|
+
{ "year": "1993", "type": "B", "value": 6 }
|
|
355
|
+
],
|
|
356
|
+
"xField": "year",
|
|
357
|
+
"yField": "value",
|
|
358
|
+
"seriesField": "type"
|
|
359
|
+
}
|
|
360
|
+
\`\`\`
|
|
361
|
+
|
|
362
|
+
\`\`\`hmchart
|
|
363
|
+
{
|
|
364
|
+
"title": "柱状图",
|
|
365
|
+
"type": "bar",
|
|
366
|
+
"data": [
|
|
367
|
+
{ "year": "1991", "value": 3 },
|
|
368
|
+
{ "year": "1992", "value": 4 },
|
|
369
|
+
{ "year": "1993", "value": 3.5 }
|
|
370
|
+
],
|
|
371
|
+
"xField": "year",
|
|
372
|
+
"yField": "value"
|
|
373
|
+
}
|
|
374
|
+
\`\`\`
|
|
375
|
+
|
|
376
|
+
\`\`\`hmchart
|
|
377
|
+
{
|
|
378
|
+
"title": "多条柱状图",
|
|
379
|
+
"type": "bar",
|
|
380
|
+
"data": [
|
|
381
|
+
{ "year": "1991", "type": "A", "value": 3 },
|
|
382
|
+
{ "year": "1991", "type": "B", "value": 4 },
|
|
383
|
+
{ "year": "1992", "type": "A", "value": 4 },
|
|
384
|
+
{ "year": "1992", "type": "B", "value": 4.5 },
|
|
385
|
+
{ "year": "1993", "type": "A", "value": 3.5 },
|
|
386
|
+
{ "year": "1993", "type": "B", "value": 6 }
|
|
387
|
+
],
|
|
388
|
+
"xField": "year",
|
|
389
|
+
"yField": "value",
|
|
390
|
+
"seriesField": "type"
|
|
391
|
+
}
|
|
392
|
+
\`\`\`
|
|
393
|
+
|
|
394
|
+
\`\`\`hmchart
|
|
395
|
+
{
|
|
396
|
+
"title": "饼图",
|
|
397
|
+
"type": "pie",
|
|
398
|
+
"data": [
|
|
399
|
+
{ "year": "1991", "value": 3 },
|
|
400
|
+
{ "year": "1992", "value": 4 },
|
|
401
|
+
{ "year": "1993", "value": 3.5 }
|
|
402
|
+
],
|
|
403
|
+
"angleField": "value",
|
|
404
|
+
"colorField": "year"
|
|
405
|
+
}
|
|
406
|
+
\`\`\`
|
|
407
|
+
|
|
408
|
+
\`\`\`hmchart
|
|
409
|
+
{
|
|
410
|
+
"title": "散点图示例",
|
|
411
|
+
"type": "scatter",
|
|
412
|
+
"data": [
|
|
413
|
+
{
|
|
414
|
+
"gender": "female",
|
|
415
|
+
"height": 161.2,
|
|
416
|
+
"weight": 51.6
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
"gender": "male",
|
|
420
|
+
"height": 167.5,
|
|
421
|
+
"weight": 59
|
|
422
|
+
},
|
|
423
|
+
{
|
|
424
|
+
"gender": "female",
|
|
425
|
+
"height": 159.5,
|
|
426
|
+
"weight": 49.2
|
|
427
|
+
},
|
|
428
|
+
{
|
|
429
|
+
"gender": "male",
|
|
430
|
+
"height": 157,
|
|
431
|
+
"weight": 63
|
|
432
|
+
},
|
|
433
|
+
{
|
|
434
|
+
"gender": "male",
|
|
435
|
+
"height": 155.8,
|
|
436
|
+
"weight": 53.6
|
|
437
|
+
},
|
|
438
|
+
{
|
|
439
|
+
"gender": "female",
|
|
440
|
+
"height": 170,
|
|
441
|
+
"weight": 59
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
"gender": "female",
|
|
445
|
+
"height": 159.1,
|
|
446
|
+
"weight": 47.6
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
"gender": "female",
|
|
450
|
+
"height": 166,
|
|
451
|
+
"weight": 69.8
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
"gender": "female",
|
|
455
|
+
"height": 176.2,
|
|
456
|
+
"weight": 66.8
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
"gender": "female",
|
|
460
|
+
"height": 160.2,
|
|
461
|
+
"weight": 75.2
|
|
462
|
+
},
|
|
463
|
+
{
|
|
464
|
+
"gender": "female",
|
|
465
|
+
"height": 172.5,
|
|
466
|
+
"weight": 55.2
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
"gender": "female",
|
|
470
|
+
"height": 170.9,
|
|
471
|
+
"weight": 54.2
|
|
472
|
+
},
|
|
473
|
+
{
|
|
474
|
+
"gender": "female",
|
|
475
|
+
"height": 172.9,
|
|
476
|
+
"weight": 62.5
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
"gender": "male",
|
|
480
|
+
"height": 153.4,
|
|
481
|
+
"weight": 42
|
|
482
|
+
},
|
|
483
|
+
{
|
|
484
|
+
"gender": "male",
|
|
485
|
+
"height": 160,
|
|
486
|
+
"weight": 50
|
|
487
|
+
}
|
|
488
|
+
],
|
|
489
|
+
"xField": "height",
|
|
490
|
+
"yField": "weight",
|
|
491
|
+
"colorField": "gender"
|
|
492
|
+
}
|
|
493
|
+
\`\`\`
|
|
494
|
+
|
|
495
|
+
`,
|
|
496
|
+
},
|
|
497
|
+
};
|