🆕 新增折线图,面积图,饼图组件

This commit is contained in:
xujiang 2020-09-20 22:57:01 +08:00
parent e209d7956e
commit f780b6bf8d
19 changed files with 565 additions and 6 deletions

BIN
src/assets/area.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
src/assets/chart copy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
src/assets/line.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
src/assets/pie.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

View File

@ -0,0 +1,13 @@
.chartWrap {
position: relative;
width: 100%;
.chartTitle {
text-align: center;
}
img {
width: 100%;
}
canvas {
width: 100%;
}
}

View File

@ -0,0 +1,76 @@
import { Chart } from '@antv/f2';
import React, { memo, useEffect, useRef } from 'react';
// import { uuid } from 'utils/tool';
import AreaImg from '@/assets/area.png';
import styles from './index.less';
import { IChartConfig } from './schema';
interface XChartProps extends IChartConfig {
isTpl: boolean;
}
const XLine = (props: XChartProps) => {
const { isTpl, data, color, size, paddingTop, title } = props;
const chartRef = useRef(null);
useEffect(() => {
if (!isTpl) {
const chart = new Chart({
el: chartRef.current || undefined,
pixelRatio: window.devicePixelRatio, // 指定分辨率
});
// step 2: 处理数据
const dataX = data.map(item => ({ ...item, value: Number(item.value), a: '1' }));
// Step 2: 载入数据源
chart.source(dataX, {
percent: {
formatter: function formatter(val) {
return val * 100 + '%';
},
},
});
chart.tooltip({
showCrosshairs: true,
});
chart.scale({
name: {
range: [0, 1],
},
value: {
tickCount: 5,
min: 0,
},
});
chart.axis('name', {
label: function label(text, index, total) {
const textCfg: any = {};
if (index === 0) {
textCfg.textAlign = 'left';
} else if (index === total - 1) {
textCfg.textAlign = 'right';
}
return textCfg;
},
});
chart.area().position('name*value');
chart.line().position('name*value');
chart.render();
}
}, [data, isTpl]);
return (
<div className={styles.chartWrap}>
<div className={styles.chartTitle} style={{ color, fontSize: size, paddingTop }}>
{title}
</div>
{isTpl ? <img src={AreaImg} alt="dooring chart" /> : <canvas ref={chartRef}></canvas>}
</div>
);
};
export default memo(XLine);

View File

@ -0,0 +1,82 @@
import {
IColorConfigType,
INumberConfigType,
ITableConfigType,
ITextConfigType,
TColorDefaultType,
TNumberDefaultType,
TTableDefaultType,
TTextDefaultType,
} from '@/components/PanelComponents/FormEditor/types';
export type TChartEditData = Array<
ITextConfigType | INumberConfigType | IColorConfigType | ITableConfigType
>;
export interface IChartConfig {
title: TTextDefaultType;
size: TNumberDefaultType;
color: TColorDefaultType;
paddingTop: TNumberDefaultType;
data: TTableDefaultType;
}
export interface IChartSchema {
editData: TChartEditData;
config: IChartConfig;
}
const Chart: IChartSchema = {
editData: [
{
key: 'title',
name: '标题',
type: 'Text',
},
{
key: 'size',
name: '标题大小',
type: 'Number',
},
{
key: 'color',
name: '标题颜色',
type: 'Color',
},
{
key: 'paddingTop',
name: '上边距',
type: 'Number',
},
{
key: 'data',
name: '数据源',
type: 'Table',
},
],
config: {
title: '面积图',
size: 14,
color: 'rgba(0,0,0,1)',
paddingTop: 10,
data: [
{
name: 'A',
value: 20,
},
{
name: 'B',
value: 60,
},
{
name: 'C',
value: 20,
},
{
name: 'D',
value: 80,
},
],
},
};
export default Chart;

View File

@ -0,0 +1,5 @@
const template = {
type: 'Area',
h: 108,
};
export default template;

View File

@ -0,0 +1,13 @@
.chartWrap {
position: relative;
width: 100%;
.chartTitle {
text-align: center;
}
img {
width: 100%;
}
canvas {
width: 100%;
}
}

View File

@ -0,0 +1,73 @@
import { Chart } from '@antv/f2';
import React, { memo, useEffect, useRef } from 'react';
// import { uuid } from 'utils/tool';
import LineImg from '@/assets/line.png';
import styles from './index.less';
import { IChartConfig } from './schema';
interface XChartProps extends IChartConfig {
isTpl: boolean;
}
const XLine = (props: XChartProps) => {
const { isTpl, data, color, size, paddingTop, title } = props;
const chartRef = useRef(null);
useEffect(() => {
if (!isTpl) {
const chart = new Chart({
el: chartRef.current || undefined,
pixelRatio: window.devicePixelRatio, // 指定分辨率
});
// step 2: 处理数据
const dataX = data.map(item => ({ ...item, value: Number(item.value) }));
// Step 2: 载入数据源
chart.source(dataX, {
value: {
tickCount: 5,
min: 0,
},
});
chart.tooltip({
showCrosshairs: true,
showItemMarker: false,
});
chart.axis('name', {
label: function label(text, index, total) {
const textCfg: any = {};
if (index === 0) {
textCfg.textAlign = 'left';
} else if (index === total - 1) {
textCfg.textAlign = 'right';
}
return textCfg;
},
});
chart.line().position('name*value');
chart
.point()
.position('name*value')
.style({
stroke: '#fff',
lineWidth: 1,
});
chart.render();
}
}, [data, isTpl]);
return (
<div className={styles.chartWrap}>
<div className={styles.chartTitle} style={{ color, fontSize: size, paddingTop }}>
{title}
</div>
{isTpl ? <img src={LineImg} alt="dooring chart" /> : <canvas ref={chartRef}></canvas>}
</div>
);
};
export default memo(XLine);

View File

@ -0,0 +1,82 @@
import {
IColorConfigType,
INumberConfigType,
ITableConfigType,
ITextConfigType,
TColorDefaultType,
TNumberDefaultType,
TTableDefaultType,
TTextDefaultType,
} from '@/components/PanelComponents/FormEditor/types';
export type TChartEditData = Array<
ITextConfigType | INumberConfigType | IColorConfigType | ITableConfigType
>;
export interface IChartConfig {
title: TTextDefaultType;
size: TNumberDefaultType;
color: TColorDefaultType;
paddingTop: TNumberDefaultType;
data: TTableDefaultType;
}
export interface IChartSchema {
editData: TChartEditData;
config: IChartConfig;
}
const Chart: IChartSchema = {
editData: [
{
key: 'title',
name: '标题',
type: 'Text',
},
{
key: 'size',
name: '标题大小',
type: 'Number',
},
{
key: 'color',
name: '标题颜色',
type: 'Color',
},
{
key: 'paddingTop',
name: '上边距',
type: 'Number',
},
{
key: 'data',
name: '数据源',
type: 'Table',
},
],
config: {
title: '折线图',
size: 14,
color: 'rgba(0,0,0,1)',
paddingTop: 10,
data: [
{
name: 'A',
value: 20,
},
{
name: 'B',
value: 60,
},
{
name: 'C',
value: 20,
},
{
name: 'D',
value: 80,
},
],
},
};
export default Chart;

View File

@ -0,0 +1,5 @@
const template = {
type: 'Line',
h: 104,
};
export default template;

View File

@ -0,0 +1,13 @@
.chartWrap {
position: relative;
width: 100%;
.chartTitle {
text-align: center;
}
img {
width: 100%;
}
canvas {
width: 100%;
}
}

View File

@ -0,0 +1,100 @@
import { Chart } from '@antv/f2';
import React, { memo, useEffect, useRef } from 'react';
// import { uuid } from 'utils/tool';
import PieImg from '@/assets/pie.png';
import styles from './index.less';
import { IChartConfig } from './schema';
interface XChartProps extends IChartConfig {
isTpl: boolean;
}
interface DataMap {
[name: string]: number | string;
}
const XLine = (props: XChartProps) => {
const { isTpl, data, color, size, paddingTop, title } = props;
const chartRef = useRef(null);
useEffect(() => {
if (!isTpl) {
const chart = new Chart({
el: chartRef.current || undefined,
pixelRatio: window.devicePixelRatio, // 指定分辨率
});
// step 2: 处理数据
const dataX = data.map(item => ({ ...item, value: Number(item.value), a: '1' }));
// Step 2: 载入数据源
chart.source(dataX, {
percent: {
formatter: function formatter(val) {
return val * 100 + '%';
},
},
});
// 获取数据的map类型用以展示图例说明
const dataMap: DataMap = dataX.reduce((prev: any, cur) => {
return prev.name
? { [prev.name]: prev.value, ...{ [cur.name]: cur.value } }
: { ...prev, ...{ [cur.name]: cur.value } };
});
chart.legend({
position: 'right',
itemFormatter: function itemFormatter(val) {
return val + ' ' + dataMap[val] + '%';
},
});
chart.tooltip(false);
chart.coord('polar', {
transposed: true,
radius: 0.85,
});
chart.axis(false);
chart
.interval()
.position('a*value')
.color('name', [
'#1890FF',
'#13C2C2',
'#2FC25B',
'#FACC14',
'#00CC99',
'#CC3366',
'#CC6600',
'#CC66CC',
'#FF3366',
'#0066CC',
])
.adjust('stack')
.style({
lineWidth: 1,
stroke: '#fff',
lineJoin: 'round',
lineCap: 'round',
})
.animate({
appear: {
duration: 1200,
easing: 'bounceOut',
},
});
chart.render();
}
}, [data, isTpl]);
return (
<div className={styles.chartWrap}>
<div className={styles.chartTitle} style={{ color, fontSize: size, paddingTop }}>
{title}
</div>
{isTpl ? <img src={PieImg} alt="dooring chart" /> : <canvas ref={chartRef}></canvas>}
</div>
);
};
export default memo(XLine);

View File

@ -0,0 +1,82 @@
import {
IColorConfigType,
INumberConfigType,
ITableConfigType,
ITextConfigType,
TColorDefaultType,
TNumberDefaultType,
TTableDefaultType,
TTextDefaultType,
} from '@/components/PanelComponents/FormEditor/types';
export type TChartEditData = Array<
ITextConfigType | INumberConfigType | IColorConfigType | ITableConfigType
>;
export interface IChartConfig {
title: TTextDefaultType;
size: TNumberDefaultType;
color: TColorDefaultType;
paddingTop: TNumberDefaultType;
data: TTableDefaultType;
}
export interface IChartSchema {
editData: TChartEditData;
config: IChartConfig;
}
const Chart: IChartSchema = {
editData: [
{
key: 'title',
name: '标题',
type: 'Text',
},
{
key: 'size',
name: '标题大小',
type: 'Number',
},
{
key: 'color',
name: '标题颜色',
type: 'Color',
},
{
key: 'paddingTop',
name: '上边距',
type: 'Number',
},
{
key: 'data',
name: '数据源',
type: 'Table',
},
],
config: {
title: '饼图',
size: 14,
color: 'rgba(0,0,0,1)',
paddingTop: 10,
data: [
{
name: 'A',
value: 20,
},
{
name: 'B',
value: 60,
},
{
name: 'C',
value: 20,
},
{
name: 'D',
value: 80,
},
],
},
};
export default Chart;

View File

@ -0,0 +1,5 @@
const template = {
type: 'Pie',
h: 106,
};
export default template;

View File

@ -1,8 +1,15 @@
import Chart from './Chart/schema';
import Line from './Line/schema';
import Pie from './Pie/schema';
import Area from './Area/schema';
import XProgress from './XProgress/schema';
const visualSchema = {
Chart,
Line,
Pie,
Area,
XProgress,
};
export default visualSchema;

View File

@ -1,7 +1,10 @@
import Chart from './Chart/template';
import Line from './Line/template';
import Pie from './Pie/template';
import Area from './Area/template';
import XProgress from './XProgress/template';
const visualTemplate = [Chart, XProgress];
const visualTemplate = [Chart, Line, Pie, Area, XProgress];
const VisualTemplate = visualTemplate.map(v => {
return { ...v, category: 'visual' };

View File

@ -1,6 +1,7 @@
import React, { useContext, useState, useEffect, useRef, memo, RefObject } from 'react';
import { Table, Input, Button, Popconfirm, Form, Modal, Upload } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import { uuid } from '@/utils/tool';
import XLSX from 'xlsx';
// 下方样式主要为全局样式,暂时不可删
import styles from './index.less';
@ -146,7 +147,6 @@ class EditableTable extends React.Component<any, any> {
this.state = {
dataSource: dataSource,
count: 2,
visible: false,
};
}
@ -159,16 +159,16 @@ class EditableTable extends React.Component<any, any> {
};
handleAdd = () => {
const { count, dataSource } = this.state;
const { dataSource } = this.state;
const uid = uuid(8, 10);
const newData = {
key: count,
name: `dooring ${count}`,
key: uid,
name: `dooring ${dataSource.length + 1}`,
value: 32,
};
const newDataSource = [...dataSource, newData];
this.setState({
dataSource: newDataSource,
count: count + 1,
});
this.props.onChange && this.props.onChange(newDataSource);
};