mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-29 18:48:45 +08:00
Echarts 配置功能
* 添加 datamapping 功能 * echarts dataMapping 不处理function * 配置改成异步加载 * 添加 打包
This commit is contained in:
parent
d08b2d69d2
commit
84f5a08c52
@ -4,14 +4,82 @@
|
||||
|
||||
import {createHierarchy} from './EChartsEditor/Common';
|
||||
import example from './EChartsEditor/Example';
|
||||
// import title from './EChartsEditor/Title';
|
||||
// import legend from './EChartsEditor/Legend';
|
||||
// import Global from './EChartsEditor/Global';
|
||||
// import Axis from './EChartsEditor/Axis';
|
||||
// import polar from './EChartsEditor/Polar';
|
||||
// import tooltip from './EChartsEditor/Tooltip';
|
||||
// import toolbox from './EChartsEditor/Toolbox';
|
||||
// import series from './EChartsEditor/Series';
|
||||
|
||||
import {lazyData} from './LazyData';
|
||||
import React from 'react';
|
||||
import {Spinner} from '../../src';
|
||||
|
||||
const LazyComponent = lazyData(
|
||||
async () =>
|
||||
(
|
||||
await Promise.all([
|
||||
import('./EChartsEditor/Title'),
|
||||
import('./EChartsEditor/Legend'),
|
||||
import('./EChartsEditor/Global'),
|
||||
import('./EChartsEditor/Axis'),
|
||||
import('./EChartsEditor/Polar'),
|
||||
import('./EChartsEditor/Tooltip'),
|
||||
import('./EChartsEditor/Toolbox'),
|
||||
import('./EChartsEditor/Series')
|
||||
])
|
||||
).map(item => item.default),
|
||||
([title, legend, Global, Axis, polar, tooltip, toolbox, series]) => {
|
||||
return ({renderFormItems}: any) => {
|
||||
return renderFormItems({
|
||||
controls: [
|
||||
createHierarchy('config', [
|
||||
{
|
||||
type: 'tabs',
|
||||
mountOnEnter: true,
|
||||
// unmountOnExit: true, // 加了更慢的样子
|
||||
mode: 'vertical',
|
||||
className: 'echarts-editor',
|
||||
tabs: [
|
||||
{
|
||||
title: '图表',
|
||||
controls: [series]
|
||||
},
|
||||
{
|
||||
title: '标题',
|
||||
controls: [title]
|
||||
},
|
||||
{
|
||||
title: '图例',
|
||||
controls: [legend]
|
||||
},
|
||||
{
|
||||
title: 'X 轴',
|
||||
controls: Axis('x')
|
||||
},
|
||||
{
|
||||
title: 'Y 轴',
|
||||
controls: Axis('y')
|
||||
},
|
||||
{
|
||||
title: '极标',
|
||||
controls: [polar]
|
||||
},
|
||||
{
|
||||
title: '提示框',
|
||||
controls: [tooltip]
|
||||
},
|
||||
{
|
||||
title: '工具栏',
|
||||
controls: [toolbox]
|
||||
},
|
||||
{
|
||||
title: '全局',
|
||||
controls: [Global]
|
||||
}
|
||||
// TODO: grid, radar, dataZoom, visualMap, axisPointer, brush, geo, parallel, parallelAxis, singleAxis, timeline, graphic, calendar, dataset, aria,
|
||||
]
|
||||
}
|
||||
])
|
||||
]
|
||||
});
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
export default {
|
||||
title: 'ECharts 编辑器',
|
||||
@ -24,74 +92,22 @@ export default {
|
||||
title: '',
|
||||
controls: [
|
||||
{
|
||||
type: 'grid',
|
||||
columns: [
|
||||
{
|
||||
sm: 12,
|
||||
md: 5,
|
||||
controls: [
|
||||
{
|
||||
type: 'chart',
|
||||
source: '${config}',
|
||||
unMountOnHidden: false
|
||||
type: 'chart',
|
||||
source: '${config}',
|
||||
replaceChartOption: true
|
||||
},
|
||||
{
|
||||
children: (props: any) => {
|
||||
return (
|
||||
<React.Suspense
|
||||
fallback={
|
||||
<Spinner overlay spinnerClassName="m-t-lg" size="lg" />
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
sm: 12,
|
||||
md: 7,
|
||||
controls: [
|
||||
createHierarchy('config', [
|
||||
{
|
||||
type: 'tabs',
|
||||
mountOnEnter: true,
|
||||
// unmountOnExit: true, // 加了更慢的样子
|
||||
mode: 'vertical',
|
||||
className: 'echarts-editor',
|
||||
tabs: [
|
||||
// {
|
||||
// title: '图表',
|
||||
// controls: [series]
|
||||
// },
|
||||
// {
|
||||
// title: '标题',
|
||||
// controls: [title]
|
||||
// },
|
||||
// {
|
||||
// title: '图例',
|
||||
// controls: [legend]
|
||||
// },
|
||||
// {
|
||||
// title: 'X 轴',
|
||||
// controls: Axis('x')
|
||||
// },
|
||||
// {
|
||||
// title: 'Y 轴',
|
||||
// controls: Axis('y')
|
||||
// },
|
||||
// {
|
||||
// title: '极标',
|
||||
// controls: [polar]
|
||||
// },
|
||||
// {
|
||||
// title: '提示框',
|
||||
// controls: [tooltip]
|
||||
// },
|
||||
// {
|
||||
// title: '工具栏',
|
||||
// controls: [toolbox]
|
||||
// },
|
||||
// {
|
||||
// title: '全局',
|
||||
// controls: [Global]
|
||||
// }
|
||||
// TODO: grid, radar, dataZoom, visualMap, axisPointer, brush, geo, parallel, parallelAxis, singleAxis, timeline, graphic, calendar, dataset, aria,
|
||||
]
|
||||
}
|
||||
])
|
||||
]
|
||||
}
|
||||
]
|
||||
>
|
||||
<LazyComponent {...props} />
|
||||
</React.Suspense>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'editor',
|
||||
|
@ -2,8 +2,6 @@
|
||||
* @file 生成一些通用的配置项
|
||||
*/
|
||||
|
||||
import {debug} from 'console';
|
||||
|
||||
/**
|
||||
* 创建一个层级,比如 name 是 title,这里面的子组件 name 就相当于 title.name
|
||||
* @param name
|
||||
@ -160,6 +158,7 @@ export const fieldSet = (
|
||||
title: label,
|
||||
collapsable: true,
|
||||
collapsed: collapsed,
|
||||
mountOnEnter: true,
|
||||
controls: controls
|
||||
};
|
||||
};
|
||||
@ -347,6 +346,7 @@ export const viewport = (scope: string, label: string) => {
|
||||
title: '离容器边距',
|
||||
collapsable: true,
|
||||
collapsed: true,
|
||||
mountOnEnter: true,
|
||||
controls: [
|
||||
...viewportControl(
|
||||
`${scope}left`,
|
||||
@ -666,6 +666,7 @@ export const shadowControls = (scope: string) => {
|
||||
title: '阴影',
|
||||
collapsable: true,
|
||||
collapsed: true,
|
||||
mountOnEnter: true,
|
||||
controls: [
|
||||
color(`${scope}shadowColor`, '阴影颜色'),
|
||||
number(`${scope}shadowBlur`, '阴影模糊大小'),
|
||||
|
@ -16,32 +16,25 @@ const buildSerieOptions = (type: string, options: any) => {
|
||||
};
|
||||
|
||||
export default {
|
||||
type: 'tabs',
|
||||
tabs: [
|
||||
type: 'combo',
|
||||
name: 'series',
|
||||
tabsMode: true,
|
||||
tabsLabelTpl: '系列${index|plus}',
|
||||
lazyLoad: true,
|
||||
label: '',
|
||||
multiLine: true,
|
||||
multiple: true,
|
||||
addButtonText: '新增系列',
|
||||
controls: [
|
||||
select('type', '图表类型', ['line', 'bar']),
|
||||
buildSerieOptions('line', lineOptions),
|
||||
{
|
||||
title: '系列',
|
||||
controls: [
|
||||
{
|
||||
type: 'combo',
|
||||
name: 'series',
|
||||
label: '',
|
||||
multiLine: true,
|
||||
multiple: true,
|
||||
addButtonText: '新增系列',
|
||||
controls: [
|
||||
select('type', '图表类型', ['line', 'bar']),
|
||||
buildSerieOptions('line', lineOptions),
|
||||
{
|
||||
type: 'array',
|
||||
name: 'data', //TODO: 目前只支持一维
|
||||
label: '数据',
|
||||
items: {
|
||||
type: 'number'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
type: 'array',
|
||||
name: 'data', //TODO: 目前只支持一维
|
||||
label: '数据',
|
||||
items: {
|
||||
type: 'number'
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
17
examples/components/LazyData.tsx
Normal file
17
examples/components/LazyData.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
|
||||
export function lazyData<T, U>(
|
||||
getData: () => Promise<U>,
|
||||
getComponent: (
|
||||
data: U
|
||||
) => React.ComponentType<T> | Promise<React.ComponentType<T>>
|
||||
) {
|
||||
return React.lazy(async () => {
|
||||
const data = await getData();
|
||||
let component = await getComponent(data);
|
||||
|
||||
return {
|
||||
default: component as React.ComponentType<T>
|
||||
};
|
||||
});
|
||||
}
|
@ -948,6 +948,7 @@ body.dark {
|
||||
// 让 echarts 编辑器的 tabs 更紧凑
|
||||
.echarts-editor > .a-Tabs-links {
|
||||
width: 4rem;
|
||||
flex-shrink: 0;
|
||||
> .a-Tabs-link > a {
|
||||
padding: 0.5rem 0.5rem;
|
||||
}
|
||||
|
@ -684,6 +684,12 @@ if (fis.project.currentMedia() === 'publish') {
|
||||
'/examples/components/App.tsx:deps'
|
||||
],
|
||||
|
||||
'pkg/echarts-editor.js': [
|
||||
'/examples/components/EChartsEditor/*.tsx',
|
||||
'!/examples/components/EChartsEditor/Example.tsx',
|
||||
'!/examples/components/EChartsEditor/Common.tsx'
|
||||
],
|
||||
|
||||
'pkg/rest.js': [
|
||||
'**.{js,jsx,ts,tsx}',
|
||||
'!static/mod.js',
|
||||
@ -760,7 +766,7 @@ if (fis.project.currentMedia() === 'publish') {
|
||||
|
||||
ghPages.match('*.{css,less,scss}', {
|
||||
optimizer: [
|
||||
function(contents) {
|
||||
function (contents) {
|
||||
if (typeof contents === 'string') {
|
||||
contents = contents.replace(/\/\*\!markdown[\s\S]*?\*\//g, '');
|
||||
}
|
||||
|
@ -354,7 +354,7 @@ export class Chart extends React.Component<ChartProps> {
|
||||
if (config) {
|
||||
try {
|
||||
if (!this.props.disableDataMapping) {
|
||||
config = dataMapping(config, this.props.data);
|
||||
config = dataMapping(config, this.props.data, true);
|
||||
}
|
||||
|
||||
recoverFunctionType(config!);
|
||||
|
@ -62,6 +62,16 @@ export interface CollapseSchema extends BaseSchema {
|
||||
* 控件大小
|
||||
*/
|
||||
size?: 'xs' | 'sm' | 'md' | 'lg' | 'base';
|
||||
|
||||
/**
|
||||
* 点开时才加载内容
|
||||
*/
|
||||
mountOnEnter?: boolean;
|
||||
|
||||
/**
|
||||
* 卡片隐藏就销毁内容。
|
||||
*/
|
||||
unmountOnExit?: boolean;
|
||||
}
|
||||
|
||||
export interface CollapseProps
|
||||
@ -88,7 +98,9 @@ export default class Collapse extends React.Component<
|
||||
'bodyClassName',
|
||||
'collapsed',
|
||||
'headingClassName',
|
||||
'title'
|
||||
'title',
|
||||
'mountOnEnter',
|
||||
'unmountOnExit'
|
||||
];
|
||||
|
||||
static defaultProps: Partial<CollapseProps> = {
|
||||
@ -146,7 +158,9 @@ export default class Collapse extends React.Component<
|
||||
bodyClassName,
|
||||
render,
|
||||
collapsable,
|
||||
translate: __
|
||||
translate: __,
|
||||
mountOnEnter,
|
||||
unmountOnExit
|
||||
} = this.props;
|
||||
// 默认给个 title,不然没法点
|
||||
const finalTitle = this.state.collapsed ? title : collapseTitle || title;
|
||||
@ -168,6 +182,8 @@ export default class Collapse extends React.Component<
|
||||
classnames={cx}
|
||||
classPrefix={ns}
|
||||
key="body"
|
||||
mountOnEnter={mountOnEnter}
|
||||
unmountOnExit={unmountOnExit}
|
||||
>
|
||||
<div className={cx(`Collapse-body`, bodyClassName)}>
|
||||
{children
|
||||
|
@ -838,9 +838,8 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
handleComboTypeChange(index: number, selection: any) {
|
||||
const {multiple, onChange, value, flat, submitOnChange} = this.props;
|
||||
|
||||
const conditions: Array<ComboCondition> = this.props.conditions as Array<
|
||||
ComboCondition
|
||||
>;
|
||||
const conditions: Array<ComboCondition> = this.props
|
||||
.conditions as Array<ComboCondition>;
|
||||
const condition = find(conditions, item => item.label === selection.label);
|
||||
|
||||
if (!condition) {
|
||||
@ -1027,6 +1026,10 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
]
|
||||
: controls;
|
||||
|
||||
const hasUnique =
|
||||
Array.isArray(finnalControls) &&
|
||||
finnalControls.some((item: any) => item.unique);
|
||||
|
||||
return (
|
||||
<Tab
|
||||
title={filter(
|
||||
@ -1038,7 +1041,7 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
toolbar={toolbar}
|
||||
eventKey={index}
|
||||
// 不能按需渲染,因为 unique 会失效。
|
||||
mountOnEnter={false}
|
||||
mountOnEnter={!hasUnique}
|
||||
unmountOnExit={false}
|
||||
>
|
||||
{condition && typeSwitchable !== false ? (
|
||||
|
@ -27,6 +27,16 @@ export interface FieldSetControlSchema
|
||||
*/
|
||||
controls?: Array<FormControlSchema>;
|
||||
|
||||
/**
|
||||
* 是否可折叠
|
||||
*/
|
||||
collapsable?: boolean;
|
||||
|
||||
/**
|
||||
* 默认是否折叠
|
||||
*/
|
||||
collapsed?: boolean;
|
||||
|
||||
/**
|
||||
* 内容区域
|
||||
*/
|
||||
@ -41,6 +51,16 @@ export interface FieldSetControlSchema
|
||||
* 收起的标题
|
||||
*/
|
||||
collapseTitle?: SchemaTpl;
|
||||
|
||||
/**
|
||||
* 点开时才加载内容
|
||||
*/
|
||||
mountOnEnter?: boolean;
|
||||
|
||||
/**
|
||||
* 卡片隐藏就销毁内容。
|
||||
*/
|
||||
unmountOnExit?: boolean;
|
||||
}
|
||||
|
||||
export interface FieldSetProps
|
||||
|
@ -590,11 +590,15 @@ function resolveMapping(
|
||||
: value;
|
||||
}
|
||||
|
||||
export function dataMapping(to: any, from: PlainObject): any {
|
||||
export function dataMapping(
|
||||
to: any,
|
||||
from: PlainObject,
|
||||
ignoreFunction = false
|
||||
): any {
|
||||
let ret = {};
|
||||
|
||||
if (Array.isArray(to)) {
|
||||
return to.map(item => dataMapping(item, from));
|
||||
return to.map(item => dataMapping(item, from, ignoreFunction));
|
||||
} else if (!to) {
|
||||
return ret;
|
||||
}
|
||||
@ -616,7 +620,11 @@ export function dataMapping(to: any, from: PlainObject): any {
|
||||
from[keys[0].substring(1)] &&
|
||||
Array.isArray(from[keys[0].substring(1)])
|
||||
? from[keys[0].substring(1)].map((raw: object) =>
|
||||
dataMapping(value[keys[0]], createObject(from, raw))
|
||||
dataMapping(
|
||||
value[keys[0]],
|
||||
createObject(from, raw),
|
||||
ignoreFunction
|
||||
)
|
||||
)
|
||||
: resolveMapping(value, from);
|
||||
|
||||
@ -663,19 +671,19 @@ export function dataMapping(to: any, from: PlainObject): any {
|
||||
const mapping = value[keys[0]];
|
||||
|
||||
(ret as PlainObject)[key] = arr.map((raw: object) =>
|
||||
dataMapping(mapping, createObject(from, raw))
|
||||
dataMapping(mapping, createObject(from, raw), ignoreFunction)
|
||||
);
|
||||
} else if (isPlainObject(value)) {
|
||||
(ret as PlainObject)[key] = dataMapping(value, from);
|
||||
(ret as PlainObject)[key] = dataMapping(value, from, ignoreFunction);
|
||||
} else if (Array.isArray(value)) {
|
||||
(ret as PlainObject)[key] = value.map((value: any) =>
|
||||
isPlainObject(value)
|
||||
? dataMapping(value, from)
|
||||
? dataMapping(value, from, ignoreFunction)
|
||||
: resolveMapping(value, from)
|
||||
);
|
||||
} else if (typeof value == 'string' && ~value.indexOf('$')) {
|
||||
(ret as PlainObject)[key] = resolveMapping(value, from);
|
||||
} else if (typeof value === 'function') {
|
||||
} else if (typeof value === 'function' && !ignoreFunction) {
|
||||
(ret as PlainObject)[key] = value(from);
|
||||
} else {
|
||||
(ret as PlainObject)[key] = value;
|
||||
|
Loading…
Reference in New Issue
Block a user