Browse Source

图表样式设置

zhuth 6 years ago
parent
commit
b628304b1a

+ 2 - 1
src/components/chartDesigner/sections/style/aggregateTable.jsx

@@ -1,6 +1,6 @@
 import React from 'react'
 import { connect } from 'dva'
-import { Collapse, Form, Radio } from 'antd'
+import { Divider, Form, Radio } from 'antd'
 import './bar.less'
 
 const FormItem = Form.Item;
@@ -39,6 +39,7 @@ class AggregateTable extends React.Component {
         const aggregateTableStyle = styleConfig.aggregateTable || {};
 
         return <Form>
+            <Divider>布局</Divider>
             <FormItem label='排布方向' {...formItemLayout}>
                 <Radio.Group onChange={e => {
                     let value = e.target.value;

+ 758 - 91
src/components/chartDesigner/sections/style/bar.jsx

@@ -1,8 +1,8 @@
 import React from 'react'
 import { connect } from 'dva'
-import { Collapse, Form, Checkbox, Select, Radio } from 'antd'
-import ColorPicker from '../../../common/colorPicker/index'
-import './bar.less'
+import { Input, InputNumber, Form, Checkbox, Select, Tooltip, Divider, Row, Col } from 'antd'
+import { deepAssign } from '../../../../utils/baseUtils'
+const FormItem = Form.Item;
 
 class BarStyle extends React.Component {
     
@@ -13,100 +13,767 @@ class BarStyle extends React.Component {
                 labelCol: { span: 8 },
                 wrapperCol: { span: 16 },
             },
-            backgroundColor: '#ffffff', // 背景
-            markTextColor: '#eeeeee', // 标签文字
-            colors: [
-                "#c23531",
-                "#2f4554",
-                "#61a0a8",
-                "#d48265",
-                "#91c7ae",
-                "#749f83",
-                "#ca8622",
-                "#bda29a",
-                "#6e7074",
-                "#546570",
-                "#c4ccd3"
-            ], // 主题
         }
     }
 
     render() {
-        const { formItemLayout, backgroundColor, colors } = this.state;
+        const { formItemLayout } = this.state;
         const { chartDesigner, dispatch } = this.props;
-        const { styleConfig } = chartDesigner;
-        const bar = styleConfig.bar || {};
+        const { styleConfig, chartOption, barConfig } = chartDesigner;
+        const { groupBy } = barConfig;
+        const barStyle = styleConfig.bar || {};
 
-        return (
-            <Collapse className='collapse-bar-style' defaultActiveKey={['chart', 'legend', 'color']}>
-                <Collapse.Panel className='chart' header='基本配置' key='chart'>
-                    <Form>
-                        <Form.Item label='背景' {...formItemLayout}>
-                            <ColorPicker placeholder={'#ffffff'} value={backgroundColor} onChange={v => {
-                                this.setState({
-                                    backgroundColor: v
-                                }, () => {
-                                    window.clearTimeout(this.backgroundColorKey);
-                                    this.backgroundColorKey = window.setTimeout(() => {
-                                        dispatch({ type: 'chartDesigner/setField', name: 'styleConfig', value: {
-                                            ...styleConfig,
-                                            bar: { ...bar, backgroundColor: v }
-                                        } });
-                                    }, 200);
-                                });
-                            }}/>
-                        </Form.Item>
-                        <Form.Item label='主题' {...formItemLayout}>
-                            { colors.map((c, i) => <ColorPicker key={i} value={colors[i]} onChange={v => {
-                                colors[i] = v
-                                this.setState({
-                                    colors,
-                                }, () => {
-                                    window.clearTimeout(this['colors-' + i + '-key']);
-                                    this['colors-' + i + '-key'] = window.setTimeout(() => {
-                                        dispatch({ type: 'chartDesigner/setField', name: 'styleConfig', value: {
-                                            ...styleConfig,
-                                            bar: { ...bar, colors: colors }
-                                        } });
-                                    }, 200);
-                                });
-                            }}/>) }
-                            <div class="colors-control"><a onClick={() => {
-                                
-                            }}>增加</a><a>减少</a></div>
-                        </Form.Item>
-                    </Form>
-                </Collapse.Panel>
-                <Collapse.Panel header='图例' key='legend'>
-                    <Form>
-                        <Form.Item label='显示' {...formItemLayout}>
-                            <Checkbox onChange={(e) => {
-                                    // const checked = e.target.checked;
-                                    // dispatch({ type: 'chartDesigner/setField', name: 'styleConfig', value: { ...styleConfig, table: { ...table, bordered: checked }} });
-                                }}/>
-                        </Form.Item>
-                        <Form.Item label='位置' {...formItemLayout}>
-                            <Select>
-                                <Select.Option value='top'>顶部</Select.Option>
-                                <Select.Option value='left'>左侧</Select.Option>
-                                <Select.Option value='bottom'>右侧</Select.Option>
-                                <Select.Option value='right'>底部</Select.Option>
-                            </Select>
-                        </Form.Item>
-                    </Form>
-                </Collapse.Panel>
-                <Collapse.Panel header='颜色' key='color'>
-                    <Form>
-                        <Form.Item label='交替色' {...formItemLayout}>
-                            <Radio.Group>
-                                <Radio value={1}>行交替</Radio>
-                                <Radio value={2}>列交替</Radio>
-                            </Radio.Group>
-                        </Form.Item>
-                    </Form>
-                </Collapse.Panel>
-            </Collapse>
-        )
+        return <Form>
+            <Divider>图域</Divider>
+            <Form.Item label='位置' {...formItemLayout}>
+                <Row>
+                    <Col span={8}>上边距:</Col>
+                    <Col span={16}>
+                        <Input
+                            key={`bar-grid-position-top-${barStyle.gridPosition ? barStyle.gridPosition['top'] : null}`}
+                            defaultValue={barStyle.gridPosition ? barStyle.gridPosition['top'] : null}
+                            placeholder={50}
+                            onBlur={e => {
+                                let value = e.target.value;
+                                let legendVisible = chartOption.legend.show,
+                                    legendOrient = chartOption.legend.orient,
+                                    legendTop = chartOption.legend.top;
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { gridPosition: { top: value} } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { grid: {
+                                        top: (value && value !== 'auto') ? ( // 已设置图域上边距
+                                            value
+                                        ) : ( // 未设置图域上边距或设置自适应
+                                            (legendVisible) ? ( // 图例未隐藏
+                                                legendOrient === 'horizontal' ? ( //图例排布方向为水平
+                                                    legendTop === 'auto' ? 50 // 已知图例上边距未设置
+                                                    : ( // 图例上边距已设置
+                                                        (legendTop+'').endsWith('%') ? (10 + Number(legendTop.replace('%', '')) + '%') // 图例上边距为百分比,图域左边距增加10%
+                                                        : (50 + Number(legendTop))// 图例上边距为数字,图域上边距增加50
+                                                    )
+                                                ) : 50
+                                            ) : 50 // 图例隐藏
+                                        ),
+                                    } }) },
+                                ] });
+                            }}
+                        />
+                    </Col>
+                </Row>
+                <Row>
+                    <Col span={8}>下边距:</Col>
+                    <Col span={16}>
+                        <Input
+                            key={`bar-grid-position-bottom-${barStyle.gridPosition ? barStyle.gridPosition['bottom'] : null}`}
+                            defaultValue={barStyle.gridPosition ? barStyle.gridPosition['bottom'] : null}
+                            placeholder={50}
+                            onBlur={e => {
+                                let value = e.target.value;
+                                let legendVisible = chartOption.legend.show,
+                                    legendOrient = chartOption.legend.orient,
+                                    legendTop = chartOption.legend.top,
+                                    legendBottom = chartOption.legend.bottom;
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { gridPosition: { bottom: value} } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { grid: {
+                                        bottom: (value && value !== 'auto') ? ( // 已设置图域下边距
+                                            value
+                                        ) : ( // 未设置图域下边距或设置自适应
+                                            (legendVisible) ? ( // 图例未隐藏
+                                                legendOrient === 'horizontal' ? ( //图例排布方向为水平
+                                                    legendTop === 'auto' ? ( // 图例上边距未设置
+                                                        legendBottom === 'auto' ? 50 // 已知图例下边距未设置
+                                                        : ( // 图例下边距已设置
+                                                            (legendBottom + '').endsWith('%') ? (10 + Number(legendBottom.replace('%', '')) + '%') // 图例下边距为百分比,图域下边距增加10%
+                                                            : (50 + Number(legendBottom))// 图例下边距为数字,图域下边距增加50
+                                                        )
+                                                    ) : 50
+                                                ) : 50
+                                            ) : 50 // 图例隐藏
+                                        ),
+                                    } }) },
+                                ] });
+                            }}
+                        />
+                    </Col>
+                </Row>
+                <Row>
+                    <Col span={8}>左边距:</Col>
+                    <Col span={16}>
+                        <Input
+                            key={`bar-grid-position-left-${barStyle.gridPosition ? barStyle.gridPosition['left'] : null}`}
+                            defaultValue={barStyle.gridPosition ? barStyle.gridPosition['left'] : null}
+                            placeholder='5%'
+                            onBlur={e => {
+                                let value = e.target.value;
+                                let legendVisible = chartOption.legend.show,
+                                    legendOrient = chartOption.legend.orient,
+                                    legendLeft = chartOption.legend.left,
+                                    legendRight = chartOption.legend.right;
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { gridPosition: { left: value} } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { grid: {
+                                        left: (value && value !== 'auto') ? ( // 已设置图域左边距
+                                            value
+                                        ) : ( // 未设置图域左边距或设置自适应
+                                            (legendVisible) ? ( // 图例未隐藏
+                                                legendOrient === 'vertical' ? ( //图例排布方向为垂直
+                                                    legendLeft === 'auto' ? ( // 已知图例左边距未设置
+                                                        legendRight === 'auto' ? '10%' // 图例右边距也未设置,将靠左对齐,图域左边距增加
+                                                        : '5%' // 图例右边距已设置
+                                                    ) : ( // 图例左边距已设置
+                                                        (legendLeft + '').endsWith('%') ? (10 + Number(legendLeft.replace('%', '')) + '%') // 图例左边距为百分比,图域左边距增加10%
+                                                        : (100 + Number(legendLeft))// 图例左边距为数字,图域左边距增加100
+                                                    )
+                                                ) : '5%'
+                                            ) : '5%' // 图例隐藏
+                                        ),
+                                    } }) },
+                                ] });
+                            }}
+                        />
+                    </Col>
+                </Row>
+                <Row>
+                    <Col span={8}>右边距:</Col>
+                    <Col span={16}>
+                        <Input
+                            key={`bar-grid-position-right-${barStyle.gridPosition ? barStyle.gridPosition['right'] : null}`}
+                            defaultValue={barStyle.gridPosition ? barStyle.gridPosition['right'] : null}
+                            placeholder='5%'
+                            onBlur={e => {
+                                let value = e.target.value;
+                                let legendVisible = chartOption.legend.show,
+                                    legendOrient = chartOption.legend.orient,
+                                    legendTop = chartOption.legend.top,
+                                    legendRight = chartOption.legend.right;
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { gridPosition: { right: value} } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { grid: {
+                                        right: (value !== '' && value !== 'auto') ? ( // 已设置图域右边距
+                                            value
+                                        ) : ( // 未设置图域右边距或设置自适应
+                                            (legendVisible) ? ( // 图例未隐藏
+                                                legendOrient === 'vertical' ? ( //图例排布方向为垂直
+                                                    legendTop === 'auto' ? ( // 图例左边距未设置
+                                                        legendRight === 'auto' ? '5%' // 已知图例右边距未设置
+                                                        : ( // 图例右边距已设置
+                                                            (legendRight + '').endsWith('%') ? (10 + Number(legendRight.replace('%', '')) + '%') // 图例右边距为百分比,图域右边距增加10%
+                                                            : (100 + Number(legendRight))// 图例右边距为数字,图域右边距增加100
+                                                        )
+                                                    ) : '5%'
+                                                ) : '5%'
+                                            ) : '5%' // 图例隐藏
+                                        )
+                                    } }) },
+                                ] });
+                            }}
+                        />
+                    </Col>
+                </Row>
+            </Form.Item>
+            <Divider>柱条</Divider>
+            <FormItem label={<Tooltip title="柱条的最大宽度,支持设置成绝对数值或相对于类目宽度的百分比">柱条最大宽度</Tooltip>} {...formItemLayout}>
+                <Input
+                    defaultValue={barStyle.barMaxWidth ? barStyle.barMaxWidth : null}
+                    placeholder='50%'
+                    onBlur={e => {
+                        let value = e.target.value;
+                        let seriesArr = [];
+                        for(let i = 0; i < chartOption.series.length; i++) {
+                            seriesArr.push({
+                                barMaxWidth: value || '50%'
+                            });
+                        }
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { barMaxWidth: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { series: seriesArr }) },
+                        ] });
+                    }}
+                />
+            </FormItem>
+            <FormItem label={<Tooltip title="柱条最小高度,可用于防止某数据项的值过小而影响交互">柱条最小高度</Tooltip>} {...formItemLayout}>
+                <InputNumber
+                    defaultValue={(barStyle.barMinHeight === '' || barStyle.barMinHeight === null || barStyle.barMinHeight === undefined) ? null : barStyle.barMinHeight}
+                    placeholder={0}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        let seriesArr = [];
+                        for(let i = 0; i < chartOption.series.length; i++) {
+                            seriesArr.push({
+                                barMinHeight: value || 0
+                            });
+                        }
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { barMinHeight: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { series: seriesArr }) },
+                        ] });
+                    }}
+                />
+            </FormItem>
+            <FormItem label={<Tooltip title="柱间距离,为相对柱子宽度的百分比。如果想要分组的柱子重叠而不使用数据堆叠,可以设置为 '-100%'">柱间距离</Tooltip>} {...formItemLayout}>
+                <Input
+                    defaultValue={barStyle.barGap ? barStyle.barGap : null}
+                    placeholder={'30%'}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        let seriesArr = [];
+                        for(let i = 0; i < chartOption.series.length; i++) {
+                            seriesArr.push({
+                                barGap: value || '30%'
+                            });
+                        }
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { barGap: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { series: seriesArr }) },
+                        ] });
+                    }}
+                />
+            </FormItem>
+            <Divider>标注</Divider>
+            <FormItem label='显示' {...formItemLayout}>
+                <Checkbox
+                    checked={!!barStyle.labelVisible}
+                    onChange={e => {
+                        let checked = e.target.checked;
+                        let seriesArr = [];
+                        for(let i = 0; i < chartOption.series.length; i++) {
+                            seriesArr.push({
+                                label: { normal: { show: checked } },
+                                labelLine: { normal: { show: checked } }
+                            });
+                        }
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { labelVisible: checked } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { series: seriesArr }) },
+                        ] });
+                    }}
+                />
+            </FormItem>
+            {!!barStyle.labelVisible && <FormItem label={<Tooltip title="{a}:系列名 {b}:数据名 {c}:数据值">格式化</Tooltip>} {...formItemLayout}>
+                <Input
+                    defaultValue={barStyle.labelFormatter ? barStyle.labelFormatter : null}
+                    placeholder={'{c}'}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        let seriesArr = [];
+                        for(let i = 0; i < chartOption.series.length; i++) {
+                            seriesArr.push({
+                                label: {
+                                    normal: { formatter: (value === '' || value === null || value === undefined) ? '{c}' : value }
+                                }
+                            });
+                        }
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { labelFormatter: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { series: seriesArr }) },
+                        ] });
+                    }}
+                />
+            </FormItem>}
+            {!!barStyle.labelVisible && <Form.Item label='位置' {...formItemLayout}>
+                <Select
+                    defaultValue={barStyle.labelPosition || 'inside'}
+                    onChange={(value, item) => {
+                        let seriesArr = [];
+                        for(let i = 0; i < chartOption.series.length; i++) {
+                            seriesArr.push({
+                                label: { normal: { position: value } }
+                            });
+                        }
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { labelPosition: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { series: seriesArr }) },
+                        ] });
+                    }}
+                >
+                    <Select.Option value='top'>外上</Select.Option>
+                    <Select.Option value='left'>外左</Select.Option>
+                    <Select.Option value='right'>外右</Select.Option>
+                    <Select.Option value='bottom'>外下</Select.Option>
+                    <Select.Option value='inside'>内中</Select.Option>
+                    <Select.Option value='insideLeft'>内左</Select.Option>
+                    <Select.Option value='insideRight'>内右</Select.Option>
+                    <Select.Option value='insideTop'>内上</Select.Option>
+                    <Select.Option value='insideBottom'>内下</Select.Option>
+                    <Select.Option value='insideTopLeft'>内上左</Select.Option>
+                    <Select.Option value='insideBottomLeft'>内下左</Select.Option>
+                    <Select.Option value='insideTopRight'>内上右</Select.Option>
+                    <Select.Option value='insideBottomRight'>内下右</Select.Option>
+                </Select>
+            </Form.Item>}
+            {!!barStyle.labelVisible && <FormItem label={<Tooltip title="标注相对设置位置方向的距离">位置距离</Tooltip>} {...formItemLayout}>
+                <InputNumber
+                    defaultValue={(barStyle.labelDistance === '' || barStyle.labelDistance === null || barStyle.labelDistance === undefined) ? null : barStyle.labelDistance}
+                    placeholder={5}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        let seriesArr = [];
+                        for(let i = 0; i < chartOption.series.length; i++) {
+                            seriesArr.push({
+                                label: {
+                                     normal: { distance: (value === '' || value === null || value === undefined) ? 5 : Number(value) }
+                                }
+                            });
+                        }
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { labelDistance: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { series: seriesArr }) },
+                        ] });
+                    }}
+                />
+            </FormItem>}
+            {!!barStyle.labelVisible && <FormItem label={<Tooltip title="标注旋转度数,正值是逆时针">旋转</Tooltip>} {...formItemLayout}>
+                <InputNumber
+                    defaultValue={(barStyle.labelRotate === '' || barStyle.labelRotate === null || barStyle.labelRotate === undefined) ? null : barStyle.labelRotate}
+                    placeholder={0}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        let seriesArr = [];
+                        for(let i = 0; i < chartOption.series.length; i++) {
+                            seriesArr.push({
+                                label: {
+                                    normal: { rotate: (value === '' || value === null || value === undefined) ? 0 : Number(value) }
+                                }
+                            });
+                        }
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { labelRotate: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { series: seriesArr }) },
+                        ] });
+                    }}
+                />
+            </FormItem>}
+            <Divider>横轴名称</Divider>
+            <FormItem label={<Tooltip title="名称相对横轴显示位置">位置</Tooltip>} {...formItemLayout}>
+                <Select
+                    defaultValue={barStyle.xNameLocation || 'end'}
+                    onChange={(value, item) => {
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { xNameLocation: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { xAxis: { 0: { 
+                                nameLocation: (value === '' || value === null || value === undefined) ? 'end' : value
+                             }} }) },
+                        ] });
+                    }}
+                >
+                    <Select.Option value='start'>头部</Select.Option>
+                    <Select.Option value='center'>中间</Select.Option>
+                    <Select.Option value='end'>尾部</Select.Option>
+                </Select>
+            </FormItem>
+            <FormItem label={<Tooltip title="横轴名称与横轴之间的距离">位置距离</Tooltip>} {...formItemLayout}>
+                <InputNumber
+                    defaultValue={(barStyle.xNameGap === '' || barStyle.xNameGap === null || barStyle.xNameGap === undefined) ? null : barStyle.xNameGap}
+                    placeholder={15}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { xNameGap: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { xAxis: { 0: {
+                                nameGap: (value === '' || value === null || value === undefined) ? 'end' : Number(value)
+                            } } }) },
+                        ] });
+                    }}
+                />
+            </FormItem>
+            <FormItem label={<Tooltip title="横轴名称旋转度数,正值是逆时针">旋转</Tooltip>} {...formItemLayout}>
+                <InputNumber
+                    defaultValue={(barStyle.xNameRotate === '' || barStyle.xNameRotate === null || barStyle.xNameRotate === undefined) ? null : barStyle.xNameRotate}
+                    placeholder={0}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { xNameRotate: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { xAxis: { 0: {
+                                nameRotate: (value === '' || value === null || value === undefined) ? 0 : Number(value)
+                            } } }) },
+                        ] });
+                    }}
+                />
+            </FormItem>
+            <Divider>横轴标签</Divider>
+            <FormItem label={<Tooltip title="当横轴标签文本全部显示会相互覆盖时可以隐藏部分标签文本">隐藏重叠标签</Tooltip>} {...formItemLayout}>
+                <Checkbox
+                    checked={barStyle.xLabelHiddenCover === undefined ? true : barStyle.xLabelHiddenCover}
+                    onChange={e => {
+                        let checked = e.target.checked;
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { xLabelHiddenCover: checked } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { xAxis: { 0: {
+                                axisLabel: {
+                                    interval: checked ? 'auto' : 0
+                                }
+                            } } }) },
+                        ] });
+                    }}
+                />
+            </FormItem>
+            {/* <FormItem label={<Tooltip title="使横轴那些超长的标签文本不要占用太多空间">最大长度</Tooltip>} {...formItemLayout}>
+                <InputNumber
+                    defaultValue={(barStyle.xLabelMaxLength === '' || barStyle.xLabelMaxLength === null || barStyle.xLabelMaxLength === undefined) ? null : barStyle.xLabelMaxLength}
+                    placeholder={8}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { xLabelMaxLength: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { xAxis: { 0: {
+                                axisLabel: {
+                                    margin: (value === '' || value === null || value === undefined) ? 8 : Number(value)
+                                }
+                            } } }) },
+                        ] });
+                    }}
+                />
+            </FormItem> */}
+            <FormItem label={<Tooltip title="横轴标签与横轴之间的距离">位置距离</Tooltip>} {...formItemLayout}>
+                <InputNumber
+                    defaultValue={(barStyle.xLabelMargin === '' || barStyle.xLabelMargin === null || barStyle.xLabelMargin === undefined) ? null : barStyle.xLabelMargin}
+                    placeholder={8}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { xLabelMargin: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { xAxis: { 0: {
+                                axisLabel: {
+                                    margin: (value === '' || value === null || value === undefined) ? 8 : Number(value)
+                                }
+                            } } }) },
+                        ] });
+                    }}
+                />
+            </FormItem>
+            <FormItem label={<Tooltip title="横轴标签旋转度数,正值是逆时针">旋转</Tooltip>} {...formItemLayout}>
+                <InputNumber
+                    defaultValue={(barStyle.xLabelRotate === '' || barStyle.xLabelRotate === null || barStyle.xLabelRotate === undefined) ? null : barStyle.xLabelRotate}
+                    placeholder={0}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { xLabelRotate: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { xAxis: { 0: {
+                                axisLabel: {
+                                    rotate: (value === '' || value === null || value === undefined) ? 0 : Number(value)
+                                }
+                            } } }) },
+                        ] });
+                    }}
+                />
+            </FormItem>
+            <Divider>纵轴名称</Divider>
+            <FormItem label={<Tooltip title="名称相对纵轴显示位置">位置</Tooltip>} {...formItemLayout}>
+                <Select
+                    defaultValue={barStyle.yNameLocation || 'end'}
+                    onChange={(value, item) => {
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { yNameLocation: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { yAxis: { 0: { 
+                                nameLocation: (value === '' || value === null || value === undefined) ? 'end' : value,
+                             }} }) },
+                        ] });
+                    }}
+                >
+                    <Select.Option value='start'>头部</Select.Option>
+                    <Select.Option value='center'>中间</Select.Option>
+                    <Select.Option value='end'>尾部</Select.Option>
+                </Select>
+            </FormItem>
+            <FormItem label={<Tooltip title="纵轴名称与纵轴之间的距离">位置距离</Tooltip>} {...formItemLayout}>
+                <InputNumber
+                    defaultValue={(barStyle.yNameGap === '' || barStyle.yNameGap === null || barStyle.yNameGap === undefined) ? null : barStyle.yNameGap}
+                    placeholder={15}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { yNameGap: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { yAxis: { 0: {
+                                nameGap: (value === '' || value === null || value === undefined) ? 'end' : Number(value)
+                            } } }) },
+                        ] });
+                    }}
+                />
+            </FormItem>
+            <FormItem label={<Tooltip title="纵轴名称旋转度数,正值是逆时针">旋转</Tooltip>} {...formItemLayout}>
+                <InputNumber
+                    defaultValue={(barStyle.yNameRotate === '' || barStyle.yNameRotate === null || barStyle.yNameRotate === undefined) ? null : barStyle.yNameRotate}
+                    placeholder={0}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { yNameRotate: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { yAxis: { 0: {
+                                nameRotate: (value === '' || value === null || value === undefined) ? 0 : Number(value)
+                            } } }) },
+                        ] });
+                    }}
+                />
+            </FormItem>
+            {!!groupBy && !!groupBy.key && <Divider>数据堆叠</Divider>}
+            {!!groupBy && !!groupBy.key && <FormItem label='数据堆叠' {...formItemLayout}>
+                <Checkbox
+                    checked={!!barStyle.stack}
+                    onChange={e => {
+                        let checked = e.target.checked;
+                        let seriesArr = [];
+                        for(let i = 0; i < chartOption.series.length; i++) {
+                            seriesArr.push({
+                                stack: checked
+                            });
+                        }
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { stack: checked } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { series: seriesArr }) },
+                        ] });
+                    }}
+                />
+            </FormItem>}
+            {!!groupBy && !!groupBy.key && <Divider>图例</Divider>}
+            {!!groupBy && !!groupBy.key && <Row>
+                <Col span={!!barStyle.legendHidden ? 24 : 12}>
+                    <Form.Item label='隐藏' labelCol={{ span: !!barStyle.legendHidden ? 8 : 16 }} wrapperCol={{ span: !!barStyle.legendHidden ? 16 : 8 }}>
+                        <Checkbox
+                            checked={!!barStyle.legendHidden}
+                            onChange={e => {
+                                let checked = e.target.checked;
+                                let legendOrient = barStyle.legendOrient || 'vertical',
+                                    legendLeft = barStyle.legendPosition ? barStyle.legendPosition.left || 'auto' : 'auto',
+                                    legendRight = barStyle.legendPosition ? barStyle.legendPosition.right || '5%' : '5%',
+                                    legendTop = barStyle.legendPosition ? barStyle.legendPosition.top || 50 : 50,
+                                    legendBottom = barStyle.legendPosition ? barStyle.legendPosition.bottom || 50 : 50,
+                                    gridPositionLeft = checked ? '5%' : ( // 隐藏图例直接将图域左边距设为5%
+                                        legendOrient === 'vertical' ? ( // 图例排布方向为垂直
+                                            legendLeft === 'auto' ? ( // 已知图例左边距未设置
+                                                legendRight === 'auto' ? '10%' // 图例右边距也未设置,将靠左对齐,图域左边距增加
+                                                : '5%' // 图例右边距已设置
+                                            ) : ( // 图例左边距已设置
+                                                (legendLeft + '').endsWith('%') ? (10 + Number(legendLeft.replace('%', '')) + '%') // 图例左边距为百分比,图域左边距增加10%
+                                                : (100 + Number(legendLeft))// 图例左边距为数字,图域左边距增加100
+                                            )
+                                        ) : '5%'
+                                    ),
+                                    gridPositionRight = checked ? '5%' : ( // 隐藏图例直接将图域右边距设为5%
+                                        legendOrient === 'vertical' ? ( // 图例排布方向为垂直
+                                            legendLeft === 'auto' ? (
+                                                legendRight === 'auto' ? '5%' // 已知图例右边距未设置
+                                                : ( // 图例右边距已设置
+                                                    (legendRight + '').endsWith('%') ? (10 + Number(legendRight.replace('%', '')) + '%') // 图例右边距为百分比,图域右边距增加10%
+                                                    : (100 + Number(legendRight))// 图例右边距为数字,图域右边距增加100
+                                                )
+                                            ) : '5%'
+                                        ) : '5%'
+                                    ),
+                                    gridPositionTop = checked ? 50:  ( // 图例未隐藏
+                                        legendOrient === 'horizontal' ? ( // 图例排布方向为水平
+                                            legendTop === 'auto' ? ( // 已知图例上边距未设置
+                                                legendBottom === 'auto' ? 50 // 图例下边距也未设置,将靠上对齐,图域上边距保持50
+                                                : 50 // 图例下边距已设置
+                                            ) : ( // 图例上边距已设置
+                                                (legendTop + '').endsWith('%') ? (10 + Number(legendTop.replace('%', '')) + '%') // 图例上边距为百分比,图域上边距增加10%
+                                                : (50 + Number(legendTop))// 图例上边距为数字,图域上边距增加50
+                                            )
+                                        ) : 50
+                                    ),
+                                    gridPositionBottom = checked ? 50 : ( // 图例未隐藏
+                                        legendOrient === 'horizontal' ? ( // 图例排布方向为水平
+                                            legendTop === 'auto' ? ( // 图例上边距未设置
+                                                legendBottom === 'auto' ? 50 // 已知图例下边距未设置
+                                                : ( // 图例下边距已设置
+                                                    (legendBottom + '').endsWith('%') ? (10 + Number(legendBottom.replace('%', '')) + '%') // 图例下边距为百分比,图域下边距增加10%
+                                                    : (50 + Number(legendBottom))// 图例下边距为数字,图域下边距增加50
+                                                )
+                                            ) : 50
+                                        ) : 50
+                                    );
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { legendHidden: checked, gridPosition: {
+                                        left: gridPositionLeft,
+                                        right: gridPositionRight,
+                                        top: gridPositionTop,
+                                        bottom: gridPositionBottom,
+                                    } } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { legend: { show: !checked }, grid: {
+                                        left: gridPositionLeft,
+                                        right: gridPositionRight,
+                                        top: gridPositionTop,
+                                        bottom: gridPositionBottom,
+                                    } }) },
+                                ] });
+                            }}
+                        />
+                    </Form.Item>
+                </Col>
+                {!!groupBy && !!groupBy.key && !barStyle.legendHidden && <Col span={12}>
+                    <Form.Item label='分页' labelCol={{ span: 16 }} wrapperCol={{ span: 8 }}>
+                        <Checkbox
+                            checked={!!barStyle.legendInPagination}
+                            onChange={e => {
+                                let checked = e.target.checked;
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { legendInPagination: checked } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { legend: { type: checked ? 'scroll' : 'plain' } }) },
+                                ] });
+                            }}
+                        />
+                    </Form.Item>
+                </Col>}
+            </Row>}
+            {!!groupBy && !!groupBy.key && !barStyle.legendHidden && <Form.Item label='排布方向' {...formItemLayout}>
+                <Select
+                    defaultValue={barStyle.legendOrient || 'vertical'}
+                    onChange={(value, item) => {
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { legendOrient: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { legend: { orient: value } }) },
+                        ] });
+                    }}
+                >
+                    <Select.Option value='vertical'>纵向排布</Select.Option>
+                    <Select.Option value='horizontal'>横向排布</Select.Option>
+                </Select>
+            </Form.Item>}
+            {!!groupBy && !!groupBy.key && !barStyle.legendHidden && <Form.Item label='位置' {...formItemLayout}>
+                <Row>
+                    <Col span={8}>上边距:</Col>
+                    <Col span={16}>
+                        <Input
+                            defaultValue={barStyle.legendPosition ? barStyle.legendPosition['top'] : null}
+                            placeholder={50}
+                            onBlur={e => {
+                                let value = e.target.value;
+                                let legendHidden = barStyle.legendHidden,
+                                    legendOrient = barStyle.legendOrient || 'vertical',
+                                    legendTop = (value === '' || value === null || value === undefined) ? 50 : value,
+                                    legendBottom = barStyle.legendPosition ? barStyle.legendPosition.bottom || 50 : 50,
+                                    gridPositionTop = !legendHidden ? ( // 图例未隐藏
+                                        legendOrient === 'horizontal' ? ( // 图例排布方向为水平
+                                            legendTop === 'auto' ? ( // 已知图例上边距未设置
+                                                legendBottom === 'auto' ? 50 // 图例下边距也未设置,将靠上对齐,图域上边距保持50
+                                                : 50 // 图例下边距已设置
+                                            ) : ( // 图例上边距已设置
+                                                (legendTop + '').endsWith('%') ? (10 + Number(legendTop.replace('%', '')) + '%') // 图例上边距为百分比,图域上边距增加10%
+                                                : (50 + Number(legendTop))// 图例上边距为数字,图域上边距增加50
+                                            )
+                                        ) : 50
+                                    ) : 50 // 图例隐藏
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { legendPosition: { top: value}, gridPosition: { top: gridPositionTop } } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { legend: {
+                                        top: legendTop,
+                                    }, grid: {
+                                        top: gridPositionTop
+                                    } }) },
+                                ] });
+                            }}
+                        />
+                    </Col>
+                </Row>
+                <Row>
+                    <Col span={8}>下边距:</Col>
+                    <Col span={16}>
+                        <Input
+                            defaultValue={barStyle.legendPosition ? barStyle.legendPosition['bottom'] : null}
+                            placeholder={50}
+                            onBlur={e => {
+                                let value = e.target.value;
+                                let legendHidden = barStyle.legendHidden,
+                                    legendOrient = barStyle.legendOrient || 'vertical',
+                                    legendTop = barStyle.legendPosition ? barStyle.legendPosition.top || 50 : 50,
+                                    legendBottom = (value === '' || value === null || value === undefined) ? 50 : value,
+                                    gridPositionBottom = !legendHidden ? ( // 图例未隐藏
+                                        legendOrient === 'horizontal' ? ( // 图例排布方向为水平
+                                            legendTop === 'auto' ? ( // 图例上边距未设置
+                                                legendBottom === 'auto' ? 50 // 已知图例下边距未设置
+                                                : ( // 图例下边距已设置
+                                                    (legendBottom + '').endsWith('%') ? (10 + Number(legendBottom.replace('%', '')) + '%') // 图例下边距为百分比,图域下边距增加10%
+                                                    : (50 + Number(legendBottom))// 图例下边距为数字,图域下边距增加50
+                                                )
+                                            ) : 50
+                                        ) : 50
+                                    ) : 50 // 图例隐藏
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { legendPosition: { bottom: value}, gridPosition: { bottom: gridPositionBottom } } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { legend: {
+                                        bottom: legendBottom
+                                    }, grid: {
+                                        bottom: gridPositionBottom
+                                    } }) },
+                                ] });
+                            }}
+                        />
+                    </Col>
+                </Row>
+                <Row>
+                    <Col span={8}>左边距:</Col>
+                    <Col span={16}>
+                        <Input
+                            defaultValue={barStyle.legendPosition ? barStyle.legendPosition['left'] : null}
+                            placeholder='auto'
+                            onBlur={e => {
+                                let value = e.target.value;
+                                let legendHidden = barStyle.legendHidden,
+                                    legendOrient = barStyle.legendOrient || 'vertical',
+                                    legendLeft = (value === '' || value === null || value === undefined) ? 'auto' : value,
+                                    legendRight = barStyle.legendPosition ? barStyle.legendPosition.right || '5%' : '5%',
+                                    gridPositionLeft = !legendHidden ? ( // 图例未隐藏
+                                        legendOrient === 'vertical' ? ( // 图例排布方向为垂直
+                                            legendLeft === 'auto' ? ( // 已知图例左边距未设置
+                                                legendRight === 'auto' ? '10%' // 图例右边距也未设置,将靠左对齐,图域左边距增加
+                                                : '5%' // 图例右边距已设置
+                                            ) : ( // 图例左边距已设置
+                                                (legendLeft + '').endsWith('%') ? (10 + Number(legendLeft.replace('%', '')) + '%') // 图例左边距为百分比,图域左边距增加10%
+                                                : (100 + Number(legendLeft))// 图例左边距为数字,图域左边距增加100
+                                            )
+                                        ) : '5%'
+                                    ) : '5%' // 图例隐藏
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { legendPosition: { left: value }, gridPosition: { left: gridPositionLeft } } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { legend: {
+                                        left: legendLeft
+                                    }, grid: {
+                                        left: gridPositionLeft
+                                    } }) },
+                                ] });
+                            }}
+                        />
+                    </Col>
+                </Row>
+                <Row>
+                    <Col span={8}>右边距:</Col>
+                    <Col span={16}>
+                        <Input
+                            defaultValue={barStyle.legendPosition ? barStyle.legendPosition['right'] : null}
+                            placeholder='5%'
+                            onBlur={e => {
+                                let value = e.target.value;
+                                let legendHidden = barStyle.legendHidden,
+                                    legendOrient = barStyle.legendOrient || 'vertical',
+                                    legendLeft = barStyle.legendPosition ? barStyle.legendPosition.left || 'auto' : 'auto',
+                                    legendRight = (value === '' || value === null || value === undefined) ? '5%' : value,
+                                    gridPositionRight = !legendHidden ? ( // 图例未隐藏
+                                        legendOrient === 'vertical' ? ( // 图例排布方向为垂直
+                                            legendLeft === 'auto' ? ( // 图例左边距未设置
+                                                legendRight === 'auto' ? '5%' // 已知图例右边距未设置
+                                                : ( // 图例右边距已设置
+                                                    (legendRight + '').endsWith('%') ? (10 + Number(legendRight.replace('%', '')) + '%') // 图例右边距为百分比,图域右边距增加10%
+                                                    : (100 + Number(legendRight))// 图例右边距为数字,图域右边距增加100
+                                                )
+                                            ) : '5%'
+                                        ) : '5%'
+                                    ) : '5%' // 图例隐藏
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { bar: { legendPosition: { right: value}, gridPosition: { right: gridPositionRight } } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { legend: {
+                                        right: legendRight
+                                    }, grid: {
+                                        right: gridPositionRight
+                                    } }) },
+                                ] });
+                            }}
+                        />
+                    </Col>
+                </Row>
+            </Form.Item>}
+        </Form>
     }
 }
 

+ 9 - 2
src/components/chartDesigner/sections/style/index.jsx

@@ -1,8 +1,11 @@
 // import TableStyle from './table'
-// import BarStyle from './bar'
+import BarStyle from './bar'
+import LineStyle from './line'
 import ThemeForm from './theme'
 import AggregateTableStyle from './aggregateTable'
 import PieStyle from './pie'
+import ScatterStyle from './scatter'
+import './index.less'
 
 export default ({ viewType }) => {
     let styleForm = <div>无可用样式配置</div>;
@@ -16,9 +19,13 @@ export default ({ viewType }) => {
     }else if(viewType === 'dataView') {
         // styleForm = <TableStyle formItemLayout={formItemLayout}/>
     }else if(viewType === 'bar') {
-        // styleForm = <BarStyle />
+        styleForm = <BarStyle />
+    }else if(viewType === 'line') {
+            styleForm = <LineStyle />
     }else if(viewType === 'pie') {
         styleForm = <PieStyle />
+    }else if(viewType === 'scatter') {
+        styleForm = <ScatterStyle />
     }
     return <div className='style-config'>
         <ThemeForm />

+ 6 - 0
src/components/chartDesigner/sections/style/index.less

@@ -0,0 +1,6 @@
+.style-config {
+    .ant-divider {
+        margin: 0;
+        font-size: 12px;
+    }
+}

+ 772 - 0
src/components/chartDesigner/sections/style/line.jsx

@@ -0,0 +1,772 @@
+import React from 'react'
+import { connect } from 'dva'
+import { Input, InputNumber, Form, Checkbox, Select, Tooltip, Divider, Row, Col } from 'antd'
+import { deepAssign } from '../../../../utils/baseUtils'
+const FormItem = Form.Item;
+
+class LineStyle extends React.Component {
+    
+    constructor(props) {
+        super(props);
+        this.state = {
+            formItemLayout: {
+                labelCol: { span: 8 },
+                wrapperCol: { span: 16 },
+            },
+        }
+    }
+
+    render() {
+        const { formItemLayout } = this.state;
+        const { chartDesigner, dispatch } = this.props;
+        const { styleConfig, chartOption, lineConfig } = chartDesigner;
+        const { groupBy } = lineConfig;
+        const lineStyle = styleConfig.line || {};
+
+        return <Form>
+            <Divider>图域</Divider>
+            <Form.Item label='位置' {...formItemLayout}>
+                <Row>
+                    <Col span={8}>上边距:</Col>
+                    <Col span={16}>
+                        <Input
+                            key={`line-grid-position-top-${lineStyle.gridPosition ? lineStyle.gridPosition['top'] : null}`}
+                            defaultValue={lineStyle.gridPosition ? lineStyle.gridPosition['top'] : null}
+                            placeholder={50}
+                            onBlur={e => {
+                                let value = e.target.value;
+                                let legendVisible = chartOption.legend.show,
+                                    legendOrient = chartOption.legend.orient,
+                                    legendTop = chartOption.legend.top;
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { line: { gridPosition: { top: value} } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { grid: {
+                                        top: (value && value !== 'auto') ? ( // 已设置图域上边距
+                                            value
+                                        ) : ( // 未设置图域上边距或设置自适应
+                                            (legendVisible) ? ( // 图例未隐藏
+                                                legendOrient === 'horizontal' ? ( //图例排布方向为水平
+                                                    legendTop === 'auto' ? 50 // 已知图例上边距未设置
+                                                    : ( // 图例上边距已设置
+                                                        (legendTop+'').endsWith('%') ? (10 + Number(legendTop.replace('%', '')) + '%') // 图例上边距为百分比,图域左边距增加10%
+                                                        : (50 + Number(legendTop))// 图例上边距为数字,图域上边距增加50
+                                                    )
+                                                ) : 50
+                                            ) : 50 // 图例隐藏
+                                        ),
+                                    } }) },
+                                ] });
+                            }}
+                        />
+                    </Col>
+                </Row>
+                <Row>
+                    <Col span={8}>下边距:</Col>
+                    <Col span={16}>
+                        <Input
+                            key={`line-grid-position-bottom-${lineStyle.gridPosition ? lineStyle.gridPosition['bottom'] : null}`}
+                            defaultValue={lineStyle.gridPosition ? lineStyle.gridPosition['bottom'] : null}
+                            placeholder={50}
+                            onBlur={e => {
+                                let value = e.target.value;
+                                let legendVisible = chartOption.legend.show,
+                                    legendOrient = chartOption.legend.orient,
+                                    legendTop = chartOption.legend.top,
+                                    legendBottom = chartOption.legend.bottom;
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { line: { gridPosition: { bottom: value} } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { grid: {
+                                        bottom: (value && value !== 'auto') ? ( // 已设置图域下边距
+                                            value
+                                        ) : ( // 未设置图域下边距或设置自适应
+                                            (legendVisible) ? ( // 图例未隐藏
+                                                legendOrient === 'horizontal' ? ( //图例排布方向为水平
+                                                    legendTop === 'auto' ? ( // 图例上边距未设置
+                                                        legendBottom === 'auto' ? 50 // 已知图例下边距未设置
+                                                        : ( // 图例下边距已设置
+                                                            (legendBottom + '').endsWith('%') ? (10 + Number(legendBottom.replace('%', '')) + '%') // 图例下边距为百分比,图域下边距增加10%
+                                                            : (50 + Number(legendBottom))// 图例下边距为数字,图域下边距增加50
+                                                        )
+                                                    ) : 50
+                                                ) : 50
+                                            ) : 50 // 图例隐藏
+                                        ),
+                                    } }) },
+                                ] });
+                            }}
+                        />
+                    </Col>
+                </Row>
+                <Row>
+                    <Col span={8}>左边距:</Col>
+                    <Col span={16}>
+                        <Input
+                            key={`line-grid-position-left-${lineStyle.gridPosition ? lineStyle.gridPosition['left'] : null}`}
+                            defaultValue={lineStyle.gridPosition ? lineStyle.gridPosition['left'] : null}
+                            placeholder='5%'
+                            onBlur={e => {
+                                let value = e.target.value;
+                                let legendVisible = chartOption.legend.show,
+                                    legendOrient = chartOption.legend.orient,
+                                    legendLeft = chartOption.legend.left,
+                                    legendRight = chartOption.legend.right;
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { line: { gridPosition: { left: value} } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { grid: {
+                                        left: (value && value !== 'auto') ? ( // 已设置图域左边距
+                                            value
+                                        ) : ( // 未设置图域左边距或设置自适应
+                                            (legendVisible) ? ( // 图例未隐藏
+                                                legendOrient === 'vertical' ? ( //图例排布方向为垂直
+                                                    legendLeft === 'auto' ? ( // 已知图例左边距未设置
+                                                        legendRight === 'auto' ? '10%' // 图例右边距也未设置,将靠左对齐,图域左边距增加
+                                                        : '5%' // 图例右边距已设置
+                                                    ) : ( // 图例左边距已设置
+                                                        (legendLeft + '').endsWith('%') ? (10 + Number(legendLeft.replace('%', '')) + '%') // 图例左边距为百分比,图域左边距增加10%
+                                                        : (100 + Number(legendLeft))// 图例左边距为数字,图域左边距增加100
+                                                    )
+                                                ) : '5%'
+                                            ) : '5%' // 图例隐藏
+                                        ),
+                                    } }) },
+                                ] });
+                            }}
+                        />
+                    </Col>
+                </Row>
+                <Row>
+                    <Col span={8}>右边距:</Col>
+                    <Col span={16}>
+                        <Input
+                            key={`line-grid-position-right-${lineStyle.gridPosition ? lineStyle.gridPosition['right'] : null}`}
+                            defaultValue={lineStyle.gridPosition ? lineStyle.gridPosition['right'] : null}
+                            placeholder='5%'
+                            onBlur={e => {
+                                let value = e.target.value;
+                                let legendVisible = chartOption.legend.show,
+                                    legendOrient = chartOption.legend.orient,
+                                    legendTop = chartOption.legend.top,
+                                    legendRight = chartOption.legend.right;
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { line: { gridPosition: { right: value} } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { grid: {
+                                        right: (value !== '' && value !== 'auto') ? ( // 已设置图域右边距
+                                            value
+                                        ) : ( // 未设置图域右边距或设置自适应
+                                            (legendVisible) ? ( // 图例未隐藏
+                                                legendOrient === 'vertical' ? ( //图例排布方向为垂直
+                                                    legendTop === 'auto' ? ( // 图例左边距未设置
+                                                        legendRight === 'auto' ? '5%' // 已知图例右边距未设置
+                                                        : ( // 图例右边距已设置
+                                                            (legendRight + '').endsWith('%') ? (10 + Number(legendRight.replace('%', '')) + '%') // 图例右边距为百分比,图域右边距增加10%
+                                                            : (100 + Number(legendRight))// 图例右边距为数字,图域右边距增加100
+                                                        )
+                                                    ) : '5%'
+                                                ) : '5%'
+                                            ) : '5%' // 图例隐藏
+                                        )
+                                    } }) },
+                                ] });
+                            }}
+                        />
+                    </Col>
+                </Row>
+            </Form.Item>
+            <Divider>线条</Divider>
+            <FormItem label='平滑线条' {...formItemLayout}>
+                <Checkbox
+                    checked={!!lineStyle.lineSmooth}
+                    onChange={e => {
+                        let checked = e.target.checked;
+                        let seriesArr = [];
+                        for(let i = 0; i < chartOption.series.length; i++) {
+                            seriesArr.push({
+                                smooth: checked
+                            });
+                        }
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { line: { lineSmooth: checked } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { series: seriesArr }) },
+                        ] });
+                    }}
+                />
+            </FormItem>
+            <Divider>标注</Divider>
+            {lineStyle.labelSymbol !== 'none' && <FormItem label='显示标注文本' {...formItemLayout}>
+                <Checkbox
+                    checked={!!lineStyle.labelVisible}
+                    onChange={e => {
+                        let checked = e.target.checked;
+                        let seriesArr = [];
+                        for(let i = 0; i < chartOption.series.length; i++) {
+                            seriesArr.push({
+                                label: { normal: { show: checked } },
+                                labelLine: { normal: { show: checked } },
+                            });
+                        }
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { line: { labelVisible: checked } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { series: seriesArr }) },
+                        ] });
+                    }}
+                />
+            </FormItem>}
+            {!!lineStyle.labelVisible && <FormItem label={<Tooltip title="{a}:系列名 {b}:数据名 {c}:数据值">格式化</Tooltip>} {...formItemLayout}>
+                <Input
+                    defaultValue={lineStyle.labelFormatter ? lineStyle.labelFormatter : null}
+                    placeholder={'{c}'}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        let seriesArr = [];
+                        for(let i = 0; i < chartOption.series.length; i++) {
+                            seriesArr.push({
+                                label: {
+                                    normal: { formatter: (value === '' || value === null || value === undefined) ? '{c}' : value }
+                                }
+                            });
+                        }
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { line: { labelFormatter: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { series: seriesArr }) },
+                        ] });
+                    }}
+                />
+            </FormItem>}
+            {!!lineStyle.labelVisible && <Form.Item label='位置' {...formItemLayout}>
+                <Select
+                    defaultValue={lineStyle.labelPosition || 'inside'}
+                    onChange={(value, item) => {
+                        let seriesArr = [];
+                        for(let i = 0; i < chartOption.series.length; i++) {
+                            seriesArr.push({
+                                label: { normal: { position: value } }
+                            });
+                        }
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { line: { labelPosition: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { series: seriesArr }) },
+                        ] });
+                    }}
+                >
+                    <Select.Option value='top'>外上</Select.Option>
+                    <Select.Option value='left'>外左</Select.Option>
+                    <Select.Option value='right'>外右</Select.Option>
+                    <Select.Option value='bottom'>外下</Select.Option>
+                    <Select.Option value='inside'>内中</Select.Option>
+                    <Select.Option value='insideLeft'>内左</Select.Option>
+                    <Select.Option value='insideRight'>内右</Select.Option>
+                    <Select.Option value='insideTop'>内上</Select.Option>
+                    <Select.Option value='insideBottom'>内下</Select.Option>
+                    <Select.Option value='insideTopLeft'>内上左</Select.Option>
+                    <Select.Option value='insideBottomLeft'>内下左</Select.Option>
+                    <Select.Option value='insideTopRight'>内上右</Select.Option>
+                    <Select.Option value='insideBottomRight'>内下右</Select.Option>
+                </Select>
+            </Form.Item>}
+            {!!lineStyle.labelVisible && <FormItem label={<Tooltip title="标注相对设置位置方向的距离">位置距离</Tooltip>} {...formItemLayout}>
+                <InputNumber
+                    defaultValue={(lineStyle.labelDistance === '' || lineStyle.labelDistance === null || lineStyle.labelDistance === undefined) ? null : lineStyle.labelDistance}
+                    placeholder={5}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        let seriesArr = [];
+                        for(let i = 0; i < chartOption.series.length; i++) {
+                            seriesArr.push({
+                                label: {
+                                    normal: { distance: (value === '' || value === null || value === undefined) ? 5 : Number(value) }
+                                }
+                            });
+                        }
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { line: { labelDistance: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { series: seriesArr }) },
+                        ] });
+                    }}
+                />
+            </FormItem>}
+            {!!lineStyle.labelVisible && <FormItem label={<Tooltip title="标注旋转度数,正值是逆时针">旋转</Tooltip>} {...formItemLayout}>
+                <InputNumber
+                    defaultValue={(lineStyle.labelRotate === '' || lineStyle.labelRotate === null || lineStyle.labelRotate === undefined) ? null : lineStyle.labelRotate}
+                    placeholder={0}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        let seriesArr = [];
+                        for(let i = 0; i < chartOption.series.length; i++) {
+                            seriesArr.push({
+                                label: {
+                                    normal: { rotate: (value === '' || value === null || value === undefined) ? 0 : Number(value) }
+                                }
+                            });
+                        }
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { line: { labelRotate: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { series: seriesArr }) },
+                        ] });
+                    }}
+                />
+            </FormItem>}
+            <Form.Item label='标注符号' {...formItemLayout}>
+                <Select
+                    defaultValue={lineStyle.labelSymbol || 'emptyCircle'}
+                    onChange={(value, item) => {
+                        let seriesArr = [];
+                        for(let i = 0; i < chartOption.series.length; i++) {
+                            seriesArr.push({
+                                symbol: value
+                            });
+                        }
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { line: { labelSymbol: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { series: seriesArr }) },
+                        ] });
+                    }}
+                >
+                    <Select.Option value='circle'>圆</Select.Option>
+                    <Select.Option value='emptyCircle'>空心圆</Select.Option>
+                    <Select.Option value='rect'>方块</Select.Option>
+                    <Select.Option value='roundRect'>圆角方块</Select.Option>
+                    <Select.Option value='triangle'>三角形</Select.Option>
+                    <Select.Option value='diamond'>菱形</Select.Option>
+                    <Select.Option value='pin'>指针</Select.Option>
+                    <Select.Option value='arrow'>箭头</Select.Option>
+                    <Select.Option value='none'>无</Select.Option>
+                </Select>
+            </Form.Item>
+            {lineStyle.labelSymbol !== 'none' && <Form.Item label='标注符号大小' {...formItemLayout}>
+                <InputNumber
+                    defaultValue={lineStyle.labelSymbolSize}
+                    placeholder={4}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        let seriesArr = [];
+                        for(let i = 0; i < chartOption.series.length; i++) {
+                            seriesArr.push({
+                                symbolSize: (value === '' || value === null || value === undefined) ? 4 : Number(value)
+                            });
+                        }
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { line: { labelSymbolSize: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { series: seriesArr }) },
+                        ] });
+                    }}
+                />
+            </Form.Item>}
+            <Divider>横轴名称</Divider>
+            <FormItem label={<Tooltip title="名称相对横轴显示位置">位置</Tooltip>} {...formItemLayout}>
+                <Select
+                    defaultValue={lineStyle.xNameLocation || 'end'}
+                    onChange={(value, item) => {
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { line: { xNameLocation: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { xAxis: { 0: { 
+                                nameLocation: (value === '' || value === null || value === undefined) ? 'end' : value
+                             }} }) },
+                        ] });
+                    }}
+                >
+                    <Select.Option value='start'>头部</Select.Option>
+                    <Select.Option value='center'>中间</Select.Option>
+                    <Select.Option value='end'>尾部</Select.Option>
+                </Select>
+            </FormItem>
+            <FormItem label={<Tooltip title="横轴名称与横轴之间的距离">位置距离</Tooltip>} {...formItemLayout}>
+                <InputNumber
+                    defaultValue={(lineStyle.xNameGap === '' || lineStyle.xNameGap === null || lineStyle.xNameGap === undefined) ? null : lineStyle.xNameGap}
+                    placeholder={15}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { line: { xNameGap: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { xAxis: { 0: {
+                                nameGap: (value === '' || value === null || value === undefined) ? 'end' : Number(value)
+                            } } }) },
+                        ] });
+                    }}
+                />
+            </FormItem>
+            <FormItem label={<Tooltip title="横轴名称旋转度数,正值是逆时针">旋转</Tooltip>} {...formItemLayout}>
+                <InputNumber
+                    defaultValue={(lineStyle.xNameRotate === '' || lineStyle.xNameRotate === null || lineStyle.xNameRotate === undefined) ? null : lineStyle.xNameRotate}
+                    placeholder={0}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { line: { xNameRotate: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { xAxis: { 0: {
+                                nameRotate: (value === '' || value === null || value === undefined) ? 0 : Number(value)
+                            } } }) },
+                        ] });
+                    }}
+                />
+            </FormItem>
+            <Divider>横轴标签</Divider>
+            {/* <FormItem label={<Tooltip title="使横轴那些超长的标签文本不要占用太多空间">最大长度</Tooltip>} {...formItemLayout}>
+                <InputNumber
+                    defaultValue={(lineStyle.xLabelMaxLength === '' || lineStyle.xLabelMaxLength === null || lineStyle.xLabelMaxLength === undefined) ? null : lineStyle.xLabelMaxLength}
+                    placeholder={8}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { line: { xLabelMaxLength: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { xAxis: { 0: {
+                                axisLabel: {
+                                    margin: (value === '' || value === null || value === undefined) ? 8 : Number(value)
+                                }
+                            } } }) },
+                        ] });
+                    }}
+                />
+            </FormItem> */}
+            <FormItem label={<Tooltip title="横轴标签与横轴之间的距离">位置距离</Tooltip>} {...formItemLayout}>
+                <InputNumber
+                    defaultValue={(lineStyle.xLabelMargin === '' || lineStyle.xLabelMargin === null || lineStyle.xLabelMargin === undefined) ? null : lineStyle.xLabelMargin}
+                    placeholder={8}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { line: { xLabelMargin: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { xAxis: { 0: {
+                                axisLabel: {
+                                    margin: (value === '' || value === null || value === undefined) ? 8 : Number(value)
+                                }
+                            } } }) },
+                        ] });
+                    }}
+                />
+            </FormItem>
+            <FormItem label={<Tooltip title="横轴标签旋转度数,正值是逆时针">旋转</Tooltip>} {...formItemLayout}>
+                <InputNumber
+                    defaultValue={(lineStyle.xLabelRotate === '' || lineStyle.xLabelRotate === null || lineStyle.xLabelRotate === undefined) ? null : lineStyle.xLabelRotate}
+                    placeholder={0}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { line: { xLabelRotate: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { xAxis: { 0: {
+                                axisLabel: {
+                                    rotate: (value === '' || value === null || value === undefined) ? 0 : Number(value)
+                                }
+                            } } }) },
+                        ] });
+                    }}
+                />
+            </FormItem>
+            <Divider>纵轴名称</Divider>
+            <FormItem label={<Tooltip title="名称相对纵轴显示位置">位置</Tooltip>} {...formItemLayout}>
+                <Select
+                    defaultValue={lineStyle.yNameLocation || 'end'}
+                    onChange={(value, item) => {
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { line: { yNameLocation: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { yAxis: { 0: { 
+                                nameLocation: (value === '' || value === null || value === undefined) ? 'end' : value,
+                                name: ((value === '' || value === null || value === undefined) ? 'end' : value) === 'center' ? chartOption.yAxis[0].name.split('').join('\n') : chartOption.yAxis[0].name.replace(/\s/g, '')
+                             }} }) },
+                        ] });
+                    }}
+                >
+                    <Select.Option value='start'>头部</Select.Option>
+                    <Select.Option value='center'>中间</Select.Option>
+                    <Select.Option value='end'>尾部</Select.Option>
+                </Select>
+            </FormItem>
+            <FormItem label={<Tooltip title="纵轴名称与纵轴之间的距离">位置距离</Tooltip>} {...formItemLayout}>
+                <InputNumber
+                    defaultValue={(lineStyle.yNameGap === '' || lineStyle.yNameGap === null || lineStyle.yNameGap === undefined) ? null : lineStyle.yNameGap}
+                    placeholder={15}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { line: { yNameGap: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { yAxis: { 0: {
+                                nameGap: (value === '' || value === null || value === undefined) ? 'end' : Number(value)
+                            } } }) },
+                        ] });
+                    }}
+                />
+            </FormItem>
+            <FormItem label={<Tooltip title="纵轴名称旋转度数,正值是逆时针">旋转</Tooltip>} {...formItemLayout}>
+                <InputNumber
+                    defaultValue={(lineStyle.yNameRotate === '' || lineStyle.yNameRotate === null || lineStyle.yNameRotate === undefined) ? null : lineStyle.yNameRotate}
+                    placeholder={0}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { line: { yNameRotate: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { yAxis: { 0: {
+                                nameRotate: (value === '' || value === null || value === undefined) ? 0 : Number(value)
+                            } } }) },
+                        ] });
+                    }}
+                />
+            </FormItem>
+            {!!groupBy && !!groupBy.key && <Divider>数据堆叠</Divider>}
+            {!!groupBy && !!groupBy.key && <FormItem label='数据堆叠' {...formItemLayout}>
+                <Checkbox
+                    checked={!!lineStyle.stack}
+                    onChange={e => {
+                        let checked = e.target.checked;
+                        let seriesArr = [];
+                        for(let i = 0; i < chartOption.series.length; i++) {
+                            seriesArr.push({
+                                stack: checked
+                            });
+                        }
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { line: { stack: checked } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { series: seriesArr }) },
+                        ] });
+                    }}
+                />
+            </FormItem>}
+            {!!groupBy && !!groupBy.key && <Divider>图例</Divider>}
+            {!!groupBy && !!groupBy.key && <Row>
+                <Col span={!!lineStyle.legendHidden ? 24 : 12}>
+                    <Form.Item label='隐藏' labelCol={{ span: !!lineStyle.legendHidden ? 8 : 16 }} wrapperCol={{ span: !!lineStyle.legendHidden ? 16 : 8 }}>
+                        <Checkbox
+                            checked={!!lineStyle.legendHidden}
+                            onChange={e => {
+                                let checked = e.target.checked;
+                                let legendOrient = lineStyle.legendOrient || 'vertical',
+                                    legendLeft = lineStyle.legendPosition ? lineStyle.legendPosition.left || 'auto' : 'auto',
+                                    legendRight = lineStyle.legendPosition ? lineStyle.legendPosition.right || '5%' : '5%',
+                                    legendTop = lineStyle.legendPosition ? lineStyle.legendPosition.top || 50 : 50,
+                                    legendBottom = lineStyle.legendPosition ? lineStyle.legendPosition.bottom || 50 : 50,
+                                    gridPositionLeft = checked ? '5%' : ( // 隐藏图例直接将图域左边距设为5%
+                                        legendOrient === 'vertical' ? ( // 图例排布方向为垂直
+                                            legendLeft === 'auto' ? ( // 已知图例左边距未设置
+                                                legendRight === 'auto' ? '10%' // 图例右边距也未设置,将靠左对齐,图域左边距增加
+                                                : '5%' // 图例右边距已设置
+                                            ) : ( // 图例左边距已设置
+                                                (legendLeft + '').endsWith('%') ? (10 + Number(legendLeft.replace('%', '')) + '%') // 图例左边距为百分比,图域左边距增加10%
+                                                : (100 + Number(legendLeft))// 图例左边距为数字,图域左边距增加100
+                                            )
+                                        ) : '5%'
+                                    ),
+                                    gridPositionRight = checked ? '5%' : ( // 隐藏图例直接将图域右边距设为5%
+                                        legendOrient === 'vertical' ? ( // 图例排布方向为垂直
+                                            legendLeft === 'auto' ? (
+                                                legendRight === 'auto' ? '5%' // 已知图例右边距未设置
+                                                : ( // 图例右边距已设置
+                                                    (legendRight + '').endsWith('%') ? (10 + Number(legendRight.replace('%', '')) + '%') // 图例右边距为百分比,图域右边距增加10%
+                                                    : (100 + Number(legendRight))// 图例右边距为数字,图域右边距增加100
+                                                )
+                                            ) : '5%'
+                                        ) : '5%'
+                                    ),
+                                    gridPositionTop = checked ? 50:  ( // 图例未隐藏
+                                        legendOrient === 'horizontal' ? ( // 图例排布方向为水平
+                                            legendTop === 'auto' ? ( // 已知图例上边距未设置
+                                                legendBottom === 'auto' ? 50 // 图例下边距也未设置,将靠上对齐,图域上边距保持50
+                                                : 50 // 图例下边距已设置
+                                            ) : ( // 图例上边距已设置
+                                                (legendTop + '').endsWith('%') ? (10 + Number(legendTop.replace('%', '')) + '%') // 图例上边距为百分比,图域上边距增加10%
+                                                : (50 + Number(legendTop))// 图例上边距为数字,图域上边距增加50
+                                            )
+                                        ) : 50
+                                    ),
+                                    gridPositionBottom = checked ? 50 : ( // 图例未隐藏
+                                        legendOrient === 'horizontal' ? ( // 图例排布方向为水平
+                                            legendTop === 'auto' ? ( // 图例上边距未设置
+                                                legendBottom === 'auto' ? 50 // 已知图例下边距未设置
+                                                : ( // 图例下边距已设置
+                                                    (legendBottom + '').endsWith('%') ? (10 + Number(legendBottom.replace('%', '')) + '%') // 图例下边距为百分比,图域下边距增加10%
+                                                    : (50 + Number(legendBottom))// 图例下边距为数字,图域下边距增加50
+                                                )
+                                            ) : 50
+                                        ) : 50
+                                    );
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { line: { legendHidden: checked, gridPosition: {
+                                        left: gridPositionLeft,
+                                        right: gridPositionRight,
+                                        top: gridPositionTop,
+                                        bottom: gridPositionBottom,
+                                    } } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { legend: { show: !checked }, grid: {
+                                        left: gridPositionLeft,
+                                        right: gridPositionRight,
+                                        top: gridPositionTop,
+                                        bottom: gridPositionBottom,
+                                    } }) },
+                                ] });
+                            }}
+                        />
+                    </Form.Item>
+                </Col>
+                {!!groupBy && !!groupBy.key && !lineStyle.legendHidden && <Col span={12}>
+                    <Form.Item label='分页' labelCol={{ span: 16 }} wrapperCol={{ span: 8 }}>
+                        <Checkbox
+                            checked={!!lineStyle.legendInPagination}
+                            onChange={e => {
+                                let checked = e.target.checked;
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { line: { legendInPagination: checked } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { legend: { type: checked ? 'scroll' : 'plain' } }) },
+                                ] });
+                            }}
+                        />
+                    </Form.Item>
+                </Col>}
+            </Row>}
+            {!!groupBy && !!groupBy.key && !lineStyle.legendHidden && <Form.Item label='排布方向' {...formItemLayout}>
+                <Select
+                    defaultValue={lineStyle.legendOrient || 'vertical'}
+                    onChange={(value, item) => {
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { line: { legendOrient: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { legend: { orient: value } }) },
+                        ] });
+                    }}
+                >
+                    <Select.Option value='vertical'>纵向排布</Select.Option>
+                    <Select.Option value='horizontal'>横向排布</Select.Option>
+                </Select>
+            </Form.Item>}
+            {!!groupBy && !!groupBy.key && !lineStyle.legendHidden && <Form.Item label='位置' {...formItemLayout}>
+                <Row>
+                    <Col span={8}>上边距:</Col>
+                    <Col span={16}>
+                        <Input
+                            defaultValue={lineStyle.legendPosition ? lineStyle.legendPosition['top'] : null}
+                            placeholder={50}
+                            onBlur={e => {
+                                let value = e.target.value;
+                                let legendHidden = lineStyle.legendHidden,
+                                    legendOrient = lineStyle.legendOrient || 'vertical',
+                                    legendTop = (value === '' || value === null || value === undefined) ? 50 : value,
+                                    legendBottom = lineStyle.legendPosition ? lineStyle.legendPosition.bottom || 50 : 50,
+                                    gridPositionTop = !legendHidden ? ( // 图例未隐藏
+                                        legendOrient === 'horizontal' ? ( // 图例排布方向为水平
+                                            legendTop === 'auto' ? ( // 已知图例上边距未设置
+                                                legendBottom === 'auto' ? 50 // 图例下边距也未设置,将靠上对齐,图域上边距保持50
+                                                : 50 // 图例下边距已设置
+                                            ) : ( // 图例上边距已设置
+                                                (legendTop + '').endsWith('%') ? (10 + Number(legendTop.replace('%', '')) + '%') // 图例上边距为百分比,图域上边距增加10%
+                                                : (50 + Number(legendTop))// 图例上边距为数字,图域上边距增加50
+                                            )
+                                        ) : 50
+                                    ) : 50 // 图例隐藏
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { line: { legendPosition: { top: value}, gridPosition: { top: gridPositionTop } } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { legend: {
+                                        top: legendTop,
+                                    }, grid: {
+                                        top: gridPositionTop
+                                    } }) },
+                                ] });
+                            }}
+                        />
+                    </Col>
+                </Row>
+                <Row>
+                    <Col span={8}>下边距:</Col>
+                    <Col span={16}>
+                        <Input
+                            defaultValue={lineStyle.legendPosition ? lineStyle.legendPosition['bottom'] : null}
+                            placeholder={50}
+                            onBlur={e => {
+                                let value = e.target.value;
+                                let legendHidden = lineStyle.legendHidden,
+                                    legendOrient = lineStyle.legendOrient || 'vertical',
+                                    legendTop = lineStyle.legendPosition ? lineStyle.legendPosition.top || 50 : 50,
+                                    legendBottom = (value === '' || value === null || value === undefined) ? 50 : value,
+                                    gridPositionBottom = !legendHidden ? ( // 图例未隐藏
+                                        legendOrient === 'horizontal' ? ( // 图例排布方向为水平
+                                            legendTop === 'auto' ? ( // 图例上边距未设置
+                                                legendBottom === 'auto' ? 50 // 已知图例下边距未设置
+                                                : ( // 图例下边距已设置
+                                                    (legendBottom + '').endsWith('%') ? (10 + Number(legendBottom.replace('%', '')) + '%') // 图例下边距为百分比,图域下边距增加10%
+                                                    : (50 + Number(legendBottom))// 图例下边距为数字,图域下边距增加50
+                                                )
+                                            ) : 50
+                                        ) : 50
+                                    ) : 50 // 图例隐藏
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { line: { legendPosition: { bottom: value}, gridPosition: { bottom: gridPositionBottom } } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { legend: {
+                                        bottom: legendBottom
+                                    }, grid: {
+                                        bottom: gridPositionBottom
+                                    } }) },
+                                ] });
+                            }}
+                        />
+                    </Col>
+                </Row>
+                <Row>
+                    <Col span={8}>左边距:</Col>
+                    <Col span={16}>
+                        <Input
+                            defaultValue={lineStyle.legendPosition ? lineStyle.legendPosition['left'] : null}
+                            placeholder='auto'
+                            onBlur={e => {
+                                let value = e.target.value;
+                                let legendHidden = lineStyle.legendHidden,
+                                    legendOrient = lineStyle.legendOrient || 'vertical',
+                                    legendLeft = (value === '' || value === null || value === undefined) ? 'auto' : value,
+                                    legendRight = lineStyle.legendPosition ? lineStyle.legendPosition.right || '5%' : '5%',
+                                    gridPositionLeft = !legendHidden ? ( // 图例未隐藏
+                                        legendOrient === 'vertical' ? ( // 图例排布方向为垂直
+                                            legendLeft === 'auto' ? ( // 已知图例左边距未设置
+                                                legendRight === 'auto' ? '10%' // 图例右边距也未设置,将靠左对齐,图域左边距增加
+                                                : '5%' // 图例右边距已设置
+                                            ) : ( // 图例左边距已设置
+                                                (legendLeft + '').endsWith('%') ? (10 + Number(legendLeft.replace('%', '')) + '%') // 图例左边距为百分比,图域左边距增加10%
+                                                : (100 + Number(legendLeft))// 图例左边距为数字,图域左边距增加100
+                                            )
+                                        ) : '5%'
+                                    ) : '5%' // 图例隐藏
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { line: { legendPosition: { left: value }, gridPosition: { left: gridPositionLeft } } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { legend: {
+                                        left: legendLeft
+                                    }, grid: {
+                                        left: gridPositionLeft
+                                    } }) },
+                                ] });
+                            }}
+                        />
+                    </Col>
+                </Row>
+                <Row>
+                    <Col span={8}>右边距:</Col>
+                    <Col span={16}>
+                        <Input
+                            defaultValue={lineStyle.legendPosition ? lineStyle.legendPosition['right'] : null}
+                            placeholder='5%'
+                            onBlur={e => {
+                                let value = e.target.value;
+                                let legendHidden = lineStyle.legendHidden,
+                                    legendOrient = lineStyle.legendOrient || 'vertical',
+                                    legendLeft = lineStyle.legendPosition ? lineStyle.legendPosition.left || 'auto' : 'auto',
+                                    legendRight = (value === '' || value === null || value === undefined) ? '5%' : value,
+                                    gridPositionRight = !legendHidden ? ( // 图例未隐藏
+                                        legendOrient === 'vertical' ? ( // 图例排布方向为垂直
+                                            legendLeft === 'auto' ? ( // 图例左边距未设置
+                                                legendRight === 'auto' ? '5%' // 已知图例右边距未设置
+                                                : ( // 图例右边距已设置
+                                                    (legendRight + '').endsWith('%') ? (10 + Number(legendRight.replace('%', '')) + '%') // 图例右边距为百分比,图域右边距增加10%
+                                                    : (100 + Number(legendRight))// 图例右边距为数字,图域右边距增加100
+                                                )
+                                            ) : '5%'
+                                        ) : '5%'
+                                    ) : '5%' // 图例隐藏
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { line: { legendPosition: { right: value}, gridPosition: { right: gridPositionRight } } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { legend: {
+                                        right: legendRight
+                                    }, grid: {
+                                        right: gridPositionRight
+                                    } }) },
+                                ] });
+                            }}
+                        />
+                    </Col>
+                </Row>
+            </Form.Item>}
+        </Form>
+    }
+}
+
+export default connect(({ present: { chartDesigner } }) => ({ chartDesigner }))(LineStyle);

+ 25 - 19
src/components/chartDesigner/sections/style/pie.jsx

@@ -1,8 +1,7 @@
 import React from 'react'
-import { Collapse, Form, Select, Divider, Row, Col, Tooltip, Input, Checkbox } from 'antd'
+import { Form, Select, Divider, Row, Col, Tooltip, Input, Checkbox } from 'antd'
 import { connect } from 'dva'
 import { deepAssign } from '../../../../utils/baseUtils'
-import themes from './theme/index'
 
 class PieStyleConfig extends React.Component {
     constructor(props) {
@@ -22,7 +21,7 @@ class PieStyleConfig extends React.Component {
         const pieStyle = styleConfig.pie || {};
 
         return <Form>
-            {/* <Divider>图形属性</Divider> */}
+            <Divider>图形</Divider>
             <Form.Item label={<Tooltip title='支持设置为数字或百分比,设置成百分比时第一项是相对于容器宽度,第二项是相对于容器高度'>圆心坐标</Tooltip>} {...formItemLayout}>
                 <Row>
                     <Col span={11}>
@@ -76,20 +75,19 @@ class PieStyleConfig extends React.Component {
                             placeholder='75%'
                             onBlur={e => {
                                 let value = e.target.value;
-                                if(value !== (!!pieStyle.pieRadius ? pieStyle.pieRadius : '')) {
-                                    dispatch({ type: 'chartDesigner/setFields', fields: [
-                                        { name: 'styleConfig', value: deepAssign(styleConfig, { pie: { pieRadius: { 1: value} } }) },
-                                        { name: 'chartOption', value: deepAssign(chartOption, { series: [ { radius: { 1: value || '75%'} }] }) },
-                                    ] });
-                                }
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { pie: { pieRadius: { 1: value} } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { series: [ { radius: { 1: value || '75%'} }] }) },
+                                ] });
                             }}
                         />
                     </Col>
                 </Row>
             </Form.Item>
+            <Divider>图例</Divider>
             <Row>
                 <Col span={!!pieStyle.legendHidden ? 24 : 12}>
-                    <Form.Item label='隐藏图例' labelCol={{ span: !!pieStyle.legendHidden ? 8 : 16 }} wrapperCol={{ span: !!pieStyle.legendHidden ? 16 : 8 }}>
+                    <Form.Item label='隐藏' labelCol={{ span: !!pieStyle.legendHidden ? 8 : 16 }} wrapperCol={{ span: !!pieStyle.legendHidden ? 16 : 8 }}>
                         <Checkbox
                             checked={!!pieStyle.legendHidden}
                             onChange={e => {
@@ -103,7 +101,7 @@ class PieStyleConfig extends React.Component {
                     </Form.Item>
                 </Col>
                 {!pieStyle.legendHidden && <Col span={12}>
-                    <Form.Item label='图例分页' labelCol={{ span: 16 }} wrapperCol={{ span: 8 }}>
+                    <Form.Item label='分页' labelCol={{ span: 16 }} wrapperCol={{ span: 8 }}>
                         <Checkbox
                             checked={!!pieStyle.legendInPagination}
                             onChange={e => {
@@ -117,10 +115,9 @@ class PieStyleConfig extends React.Component {
                     </Form.Item>
                 </Col>}
             </Row>
-            {!pieStyle.legendHidden && <Form.Item label='图例排布方向' {...formItemLayout}>
+            {!pieStyle.legendHidden && <Form.Item label='排布方向' {...formItemLayout}>
                 <Select
                     defaultValue={pieStyle.legendOrient || 'vertical'}
-                    placeholder='vertical'
                     onChange={(value, item) => {
                         dispatch({ type: 'chartDesigner/setFields', fields: [
                             { name: 'styleConfig', value: deepAssign(styleConfig, { pie: { legendOrient: value } }) },
@@ -132,7 +129,7 @@ class PieStyleConfig extends React.Component {
                     <Select.Option value='horizontal'>横向排布</Select.Option>
                 </Select>
             </Form.Item>}
-            {!pieStyle.legendHidden && <Form.Item label='图例位置' {...formItemLayout}>
+            {!pieStyle.legendHidden && <Form.Item label='位置' {...formItemLayout}>
                 <Row>
                     <Col span={8}>上边距:</Col>
                     <Col span={16}>
@@ -143,7 +140,9 @@ class PieStyleConfig extends React.Component {
                                 let value = e.target.value;
                                 dispatch({ type: 'chartDesigner/setFields', fields: [
                                     { name: 'styleConfig', value: deepAssign(styleConfig, { pie: { legendPosition: { top: value} } }) },
-                                    { name: 'chartOption', value: deepAssign(chartOption, { legend: { top: value } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { legend: {
+                                        top: (value === '' || value === null || value === undefined) ? 50 : value
+                                    } }) },
                                 ] });
                             }}
                         />
@@ -159,7 +158,9 @@ class PieStyleConfig extends React.Component {
                                 let value = e.target.value;
                                 dispatch({ type: 'chartDesigner/setFields', fields: [
                                     { name: 'styleConfig', value: deepAssign(styleConfig, { pie: { legendPosition: { bottom: value} } }) },
-                                    { name: 'chartOption', value: deepAssign(chartOption, { legend: { bottom: value } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { legend: {
+                                        bottom: (value === '' || value === null || value === undefined) ? 50 : value
+                                    } }) },
                                 ] });
                             }}
                         />
@@ -175,7 +176,9 @@ class PieStyleConfig extends React.Component {
                                 let value = e.target.value;
                                 dispatch({ type: 'chartDesigner/setFields', fields: [
                                     { name: 'styleConfig', value: deepAssign(styleConfig, { pie: { legendPosition: { left: value} } }) },
-                                    { name: 'chartOption', value: deepAssign(chartOption, { legend: { left: value } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { legend: {
+                                        left: (value === '' || value === null || value === undefined) ? 'auto' : value
+                                    } }) },
                                 ] });
                             }}
                         />
@@ -191,7 +194,9 @@ class PieStyleConfig extends React.Component {
                                 let value = e.target.value;
                                 dispatch({ type: 'chartDesigner/setFields', fields: [
                                     { name: 'styleConfig', value: deepAssign(styleConfig, { pie: { legendPosition: { right: value} } }) },
-                                    { name: 'chartOption', value: deepAssign(chartOption, { legend: { right: value } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { legend: {
+                                        right: (value === '' || value === null || value === undefined) ? '10%' : value
+                                    } }) },
                                 ] });
                             }}
                         />
@@ -230,7 +235,8 @@ class PieStyleConfig extends React.Component {
                     }}
                 />
             </Form.Item> */}
-            <Form.Item label='隐藏标注' {...formItemLayout}>
+            <Divider>标注</Divider>
+            <Form.Item label='隐藏' {...formItemLayout}>
                 <Checkbox
                     checked={!!pieStyle.labelHidden}
                     onChange={e => {

+ 603 - 0
src/components/chartDesigner/sections/style/scatter.jsx

@@ -0,0 +1,603 @@
+import React from 'react'
+import { connect } from 'dva'
+import { Input, InputNumber, Form, Checkbox, Select, Tooltip, Divider, Row, Col } from 'antd'
+import { deepAssign } from '../../../../utils/baseUtils'
+const FormItem = Form.Item;
+
+class ScatterStyle extends React.Component {
+    
+    constructor(props) {
+        super(props);
+        this.state = {
+            formItemLayout: {
+                labelCol: { span: 8 },
+                wrapperCol: { span: 16 },
+            },
+        }
+    }
+
+    render() {
+        const { formItemLayout } = this.state;
+        const { chartDesigner, dispatch } = this.props;
+        const { styleConfig, chartOption, scatterConfig } = chartDesigner;
+        const { groupBy } = scatterConfig;
+        const scatterStyle = styleConfig.scatter || {};
+
+        return <Form>
+            <Divider>图域</Divider>
+            <Form.Item label='位置' {...formItemLayout}>
+                <Row>
+                    <Col span={8}>上边距:</Col>
+                    <Col span={16}>
+                        <Input
+                            key={`scatter-grid-position-top-${scatterStyle.gridPosition ? scatterStyle.gridPosition['top'] : null}`}
+                            defaultValue={scatterStyle.gridPosition ? scatterStyle.gridPosition['top'] : null}
+                            placeholder={50}
+                            onBlur={e => {
+                                let value = e.target.value;
+                                let legendVisible = chartOption.legend.show,
+                                    legendOrient = chartOption.legend.orient,
+                                    legendTop = chartOption.legend.top;
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { scatter: { gridPosition: { top: value} } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { grid: {
+                                        top: (value && value !== 'auto') ? ( // 已设置图域上边距
+                                            value
+                                        ) : ( // 未设置图域上边距或设置自适应
+                                            (legendVisible) ? ( // 图例未隐藏
+                                                legendOrient === 'horizontal' ? ( //图例排布方向为水平
+                                                    legendTop === 'auto' ? 50 // 已知图例上边距未设置
+                                                    : ( // 图例上边距已设置
+                                                        (legendTop+'').endsWith('%') ? (10 + Number(legendTop.replace('%', '')) + '%') // 图例上边距为百分比,图域左边距增加10%
+                                                        : (50 + Number(legendTop))// 图例上边距为数字,图域上边距增加50
+                                                    )
+                                                ) : 50
+                                            ) : 50 // 图例隐藏
+                                        ),
+                                    } }) },
+                                ] });
+                            }}
+                        />
+                    </Col>
+                </Row>
+                <Row>
+                    <Col span={8}>下边距:</Col>
+                    <Col span={16}>
+                        <Input
+                            key={`scatter-grid-position-bottom-${scatterStyle.gridPosition ? scatterStyle.gridPosition['bottom'] : null}`}
+                            defaultValue={scatterStyle.gridPosition ? scatterStyle.gridPosition['bottom'] : null}
+                            placeholder={50}
+                            onBlur={e => {
+                                let value = e.target.value;
+                                let legendVisible = chartOption.legend.show,
+                                    legendOrient = chartOption.legend.orient,
+                                    legendTop = chartOption.legend.top,
+                                    legendBottom = chartOption.legend.bottom;
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { scatter: { gridPosition: { bottom: value} } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { grid: {
+                                        bottom: (value && value !== 'auto') ? ( // 已设置图域下边距
+                                            value
+                                        ) : ( // 未设置图域下边距或设置自适应
+                                            (legendVisible) ? ( // 图例未隐藏
+                                                legendOrient === 'horizontal' ? ( //图例排布方向为水平
+                                                    legendTop === 'auto' ? ( // 图例上边距未设置
+                                                        legendBottom === 'auto' ? 50 // 已知图例下边距未设置
+                                                        : ( // 图例下边距已设置
+                                                            (legendBottom + '').endsWith('%') ? (10 + Number(legendBottom.replace('%', '')) + '%') // 图例下边距为百分比,图域下边距增加10%
+                                                            : (50 + Number(legendBottom))// 图例下边距为数字,图域下边距增加50
+                                                        )
+                                                    ) : 50
+                                                ) : 50
+                                            ) : 50 // 图例隐藏
+                                        ),
+                                    } }) },
+                                ] });
+                            }}
+                        />
+                    </Col>
+                </Row>
+                <Row>
+                    <Col span={8}>左边距:</Col>
+                    <Col span={16}>
+                        <Input
+                            key={`scatter-grid-position-left-${scatterStyle.gridPosition ? scatterStyle.gridPosition['left'] : null}`}
+                            defaultValue={scatterStyle.gridPosition ? scatterStyle.gridPosition['left'] : null}
+                            placeholder='5%'
+                            onBlur={e => {
+                                let value = e.target.value;
+                                let legendVisible = chartOption.legend.show,
+                                    legendOrient = chartOption.legend.orient,
+                                    legendLeft = chartOption.legend.left,
+                                    legendRight = chartOption.legend.right;
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { scatter: { gridPosition: { left: value} } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { grid: {
+                                        left: (value && value !== 'auto') ? ( // 已设置图域左边距
+                                            value
+                                        ) : ( // 未设置图域左边距或设置自适应
+                                            (legendVisible) ? ( // 图例未隐藏
+                                                legendOrient === 'vertical' ? ( //图例排布方向为垂直
+                                                    legendLeft === 'auto' ? ( // 已知图例左边距未设置
+                                                        legendRight === 'auto' ? '10%' // 图例右边距也未设置,将靠左对齐,图域左边距增加
+                                                        : '5%' // 图例右边距已设置
+                                                    ) : ( // 图例左边距已设置
+                                                        (legendLeft + '').endsWith('%') ? (10 + Number(legendLeft.replace('%', '')) + '%') // 图例左边距为百分比,图域左边距增加10%
+                                                        : (100 + Number(legendLeft))// 图例左边距为数字,图域左边距增加100
+                                                    )
+                                                ) : '5%'
+                                            ) : '5%' // 图例隐藏
+                                        ),
+                                    } }) },
+                                ] });
+                            }}
+                        />
+                    </Col>
+                </Row>
+                <Row>
+                    <Col span={8}>右边距:</Col>
+                    <Col span={16}>
+                        <Input
+                            key={`scatter-grid-position-right-${scatterStyle.gridPosition ? scatterStyle.gridPosition['right'] : null}`}
+                            defaultValue={scatterStyle.gridPosition ? scatterStyle.gridPosition['right'] : null}
+                            placeholder='5%'
+                            onBlur={e => {
+                                let value = e.target.value;
+                                let legendVisible = chartOption.legend.show,
+                                    legendOrient = chartOption.legend.orient,
+                                    legendTop = chartOption.legend.top,
+                                    legendRight = chartOption.legend.right;
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { scatter: { gridPosition: { right: value} } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { grid: {
+                                        right: (value !== '' && value !== 'auto') ? ( // 已设置图域右边距
+                                            value
+                                        ) : ( // 未设置图域右边距或设置自适应
+                                            (legendVisible) ? ( // 图例未隐藏
+                                                legendOrient === 'vertical' ? ( //图例排布方向为垂直
+                                                    legendTop === 'auto' ? ( // 图例左边距未设置
+                                                        legendRight === 'auto' ? '5%' // 已知图例右边距未设置
+                                                        : ( // 图例右边距已设置
+                                                            (legendRight + '').endsWith('%') ? (10 + Number(legendRight.replace('%', '')) + '%') // 图例右边距为百分比,图域右边距增加10%
+                                                            : (100 + Number(legendRight))// 图例右边距为数字,图域右边距增加100
+                                                        )
+                                                    ) : '5%'
+                                                ) : '5%'
+                                            ) : '5%' // 图例隐藏
+                                        )
+                                    } }) },
+                                ] });
+                            }}
+                        />
+                    </Col>
+                </Row>
+            </Form.Item>
+            <Divider>标注</Divider>
+            <Form.Item label='标注符号' {...formItemLayout}>
+                <Select
+                    defaultValue={scatterStyle.labelSymbol || 'circle'}
+                    onChange={(value, item) => {
+                        let seriesArr = [];
+                        for(let i = 0; i < chartOption.series.length; i++) {
+                            seriesArr.push({
+                                symbol: value
+                            });
+                        }
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { scatter: { labelSymbol: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { series: seriesArr }) },
+                        ] });
+                    }}
+                >
+                    <Select.Option value='circle'>圆</Select.Option>
+                    <Select.Option value='emptyCircle'>空心圆</Select.Option>
+                    <Select.Option value='rect'>方块</Select.Option>
+                    <Select.Option value='roundRect'>圆角方块</Select.Option>
+                    <Select.Option value='triangle'>三角形</Select.Option>
+                    <Select.Option value='diamond'>菱形</Select.Option>
+                    <Select.Option value='pin'>指针</Select.Option>
+                    <Select.Option value='arrow'>箭头</Select.Option>
+                    <Select.Option value='none'>无</Select.Option>
+                </Select>
+            </Form.Item>
+            {scatterStyle.labelSymbol !== 'none' && <Form.Item label='标注符号大小' {...formItemLayout}>
+                <InputNumber
+                    defaultValue={scatterStyle.labelSymbolSize}
+                    placeholder={10}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        let seriesArr = [];
+                        for(let i = 0; i < chartOption.series.length; i++) {
+                            seriesArr.push({
+                                symbolSize: (value === '' || value === null || value === undefined) ? 10 : Number(value)
+                            });
+                        }
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { scatter: { labelSymbolSize: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { series: seriesArr }) },
+                        ] });
+                    }}
+                />
+            </Form.Item>}
+            <Divider>横轴名称</Divider>
+            <FormItem label={<Tooltip title="名称相对横轴显示位置">位置</Tooltip>} {...formItemLayout}>
+                <Select
+                    defaultValue={scatterStyle.xNameLocation || 'end'}
+                    onChange={(value, item) => {
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { scatter: { xNameLocation: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { xAxis: { 0: { 
+                                nameLocation: (value === '' || value === null || value === undefined) ? 'end' : value
+                             }} }) },
+                        ] });
+                    }}
+                >
+                    <Select.Option value='start'>头部</Select.Option>
+                    <Select.Option value='center'>中间</Select.Option>
+                    <Select.Option value='end'>尾部</Select.Option>
+                </Select>
+            </FormItem>
+            <FormItem label={<Tooltip title="横轴名称与横轴之间的距离">位置距离</Tooltip>} {...formItemLayout}>
+                <InputNumber
+                    defaultValue={(scatterStyle.xNameGap === '' || scatterStyle.xNameGap === null || scatterStyle.xNameGap === undefined) ? null : scatterStyle.xNameGap}
+                    placeholder={15}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { scatter: { xNameGap: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { xAxis: { 0: {
+                                nameGap: (value === '' || value === null || value === undefined) ? 'end' : Number(value)
+                            } } }) },
+                        ] });
+                    }}
+                />
+            </FormItem>
+            <FormItem label={<Tooltip title="横轴名称旋转度数,正值是逆时针">旋转</Tooltip>} {...formItemLayout}>
+                <InputNumber
+                    defaultValue={(scatterStyle.xNameRotate === '' || scatterStyle.xNameRotate === null || scatterStyle.xNameRotate === undefined) ? null : scatterStyle.xNameRotate}
+                    placeholder={0}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { scatter: { xNameRotate: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { xAxis: { 0: {
+                                nameRotate: (value === '' || value === null || value === undefined) ? 0 : Number(value)
+                            } } }) },
+                        ] });
+                    }}
+                />
+            </FormItem>
+            <Divider>横轴标签</Divider>
+            <FormItem label={<Tooltip title="横轴标签与横轴之间的距离">位置距离</Tooltip>} {...formItemLayout}>
+                <InputNumber
+                    defaultValue={(scatterStyle.xLabelMargin === '' || scatterStyle.xLabelMargin === null || scatterStyle.xLabelMargin === undefined) ? null : scatterStyle.xLabelMargin}
+                    placeholder={8}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { scatter: { xLabelMargin: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { xAxis: { 0: {
+                                axisLabel: {
+                                    margin: (value === '' || value === null || value === undefined) ? 8 : Number(value)
+                                }
+                            } } }) },
+                        ] });
+                    }}
+                />
+            </FormItem>
+            <FormItem label={<Tooltip title="横轴标签旋转度数,正值是逆时针">旋转</Tooltip>} {...formItemLayout}>
+                <InputNumber
+                    defaultValue={(scatterStyle.xLabelRotate === '' || scatterStyle.xLabelRotate === null || scatterStyle.xLabelRotate === undefined) ? null : scatterStyle.xLabelRotate}
+                    placeholder={0}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { scatter: { xLabelRotate: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { xAxis: { 0: {
+                                axisLabel: {
+                                    rotate: (value === '' || value === null || value === undefined) ? 0 : Number(value)
+                                }
+                            } } }) },
+                        ] });
+                    }}
+                />
+            </FormItem>
+            <Divider>纵轴名称</Divider>
+            <FormItem label={<Tooltip title="名称相对纵轴显示位置">位置</Tooltip>} {...formItemLayout}>
+                <Select
+                    defaultValue={scatterStyle.yNameLocation || 'end'}
+                    onChange={(value, item) => {
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { scatter: { yNameLocation: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { yAxis: { 0: { 
+                                nameLocation: (value === '' || value === null || value === undefined) ? 'end' : value,
+                             }} }) },
+                        ] });
+                    }}
+                >
+                    <Select.Option value='start'>头部</Select.Option>
+                    <Select.Option value='center'>中间</Select.Option>
+                    <Select.Option value='end'>尾部</Select.Option>
+                </Select>
+            </FormItem>
+            <FormItem label={<Tooltip title="纵轴名称与纵轴之间的距离">位置距离</Tooltip>} {...formItemLayout}>
+                <InputNumber
+                    defaultValue={(scatterStyle.yNameGap === '' || scatterStyle.yNameGap === null || scatterStyle.yNameGap === undefined) ? null : scatterStyle.yNameGap}
+                    placeholder={15}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { scatter: { yNameGap: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { yAxis: { 0: {
+                                nameGap: (value === '' || value === null || value === undefined) ? 'end' : Number(value)
+                            } } }) },
+                        ] });
+                    }}
+                />
+            </FormItem>
+            <FormItem label={<Tooltip title="纵轴名称旋转度数,正值是逆时针">旋转</Tooltip>} {...formItemLayout}>
+                <InputNumber
+                    defaultValue={(scatterStyle.yNameRotate === '' || scatterStyle.yNameRotate === null || scatterStyle.yNameRotate === undefined) ? null : scatterStyle.yNameRotate}
+                    placeholder={0}
+                    onBlur={e => {
+                        let value = e.target.value;
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { scatter: { yNameRotate: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { yAxis: { 0: {
+                                nameRotate: (value === '' || value === null || value === undefined) ? 0 : Number(value)
+                            } } }) },
+                        ] });
+                    }}
+                />
+            </FormItem>
+            {!!groupBy && !!groupBy.key && <Divider>图例</Divider>}
+            {!!groupBy && !!groupBy.key && <Row>
+                <Col span={!!scatterStyle.legendHidden ? 24 : 12}>
+                    <Form.Item label='隐藏' labelCol={{ span: !!scatterStyle.legendHidden ? 8 : 16 }} wrapperCol={{ span: !!scatterStyle.legendHidden ? 16 : 8 }}>
+                        <Checkbox
+                            checked={!!scatterStyle.legendHidden}
+                            onChange={e => {
+                                let checked = e.target.checked;
+                                let legendOrient = scatterStyle.legendOrient || 'vertical',
+                                    legendLeft = scatterStyle.legendPosition ? scatterStyle.legendPosition.left || 'auto' : 'auto',
+                                    legendRight = scatterStyle.legendPosition ? scatterStyle.legendPosition.right || '5%' : '5%',
+                                    legendTop = scatterStyle.legendPosition ? scatterStyle.legendPosition.top || 50 : 50,
+                                    legendBottom = scatterStyle.legendPosition ? scatterStyle.legendPosition.bottom || 50 : 50,
+                                    gridPositionLeft = checked ? '5%' : ( // 隐藏图例直接将图域左边距设为5%
+                                        legendOrient === 'vertical' ? ( // 图例排布方向为垂直
+                                            legendLeft === 'auto' ? ( // 已知图例左边距未设置
+                                                legendRight === 'auto' ? '10%' // 图例右边距也未设置,将靠左对齐,图域左边距增加
+                                                : '5%' // 图例右边距已设置
+                                            ) : ( // 图例左边距已设置
+                                                (legendLeft + '').endsWith('%') ? (10 + Number(legendLeft.replace('%', '')) + '%') // 图例左边距为百分比,图域左边距增加10%
+                                                : (100 + Number(legendLeft))// 图例左边距为数字,图域左边距增加100
+                                            )
+                                        ) : '5%'
+                                    ),
+                                    gridPositionRight = checked ? '5%' : ( // 隐藏图例直接将图域右边距设为5%
+                                        legendOrient === 'vertical' ? ( // 图例排布方向为垂直
+                                            legendLeft === 'auto' ? (
+                                                legendRight === 'auto' ? '5%' // 已知图例右边距未设置
+                                                : ( // 图例右边距已设置
+                                                    (legendRight + '').endsWith('%') ? (10 + Number(legendRight.replace('%', '')) + '%') // 图例右边距为百分比,图域右边距增加10%
+                                                    : (100 + Number(legendRight))// 图例右边距为数字,图域右边距增加100
+                                                )
+                                            ) : '5%'
+                                        ) : '5%'
+                                    ),
+                                    gridPositionTop = checked ? 50:  ( // 图例未隐藏
+                                        legendOrient === 'horizontal' ? ( // 图例排布方向为水平
+                                            legendTop === 'auto' ? ( // 已知图例上边距未设置
+                                                legendBottom === 'auto' ? 50 // 图例下边距也未设置,将靠上对齐,图域上边距保持50
+                                                : 50 // 图例下边距已设置
+                                            ) : ( // 图例上边距已设置
+                                                (legendTop + '').endsWith('%') ? (10 + Number(legendTop.replace('%', '')) + '%') // 图例上边距为百分比,图域上边距增加10%
+                                                : (50 + Number(legendTop))// 图例上边距为数字,图域上边距增加50
+                                            )
+                                        ) : 50
+                                    ),
+                                    gridPositionBottom = checked ? 50 : ( // 图例未隐藏
+                                        legendOrient === 'horizontal' ? ( // 图例排布方向为水平
+                                            legendTop === 'auto' ? ( // 图例上边距未设置
+                                                legendBottom === 'auto' ? 50 // 已知图例下边距未设置
+                                                : ( // 图例下边距已设置
+                                                    (legendBottom + '').endsWith('%') ? (10 + Number(legendBottom.replace('%', '')) + '%') // 图例下边距为百分比,图域下边距增加10%
+                                                    : (50 + Number(legendBottom))// 图例下边距为数字,图域下边距增加50
+                                                )
+                                            ) : 50
+                                        ) : 50
+                                    );
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { scatter: { legendHidden: checked, gridPosition: {
+                                        left: gridPositionLeft,
+                                        right: gridPositionRight,
+                                        top: gridPositionTop,
+                                        bottom: gridPositionBottom,
+                                    } } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { legend: { show: !checked }, grid: {
+                                        left: gridPositionLeft,
+                                        right: gridPositionRight,
+                                        top: gridPositionTop,
+                                        bottom: gridPositionBottom,
+                                    } }) },
+                                ] });
+                            }}
+                        />
+                    </Form.Item>
+                </Col>
+                {!!groupBy && !!groupBy.key && !scatterStyle.legendHidden && <Col span={12}>
+                    <Form.Item label='分页' labelCol={{ span: 16 }} wrapperCol={{ span: 8 }}>
+                        <Checkbox
+                            checked={!!scatterStyle.legendInPagination}
+                            onChange={e => {
+                                let checked = e.target.checked;
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { scatter: { legendInPagination: checked } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { legend: { type: checked ? 'scroll' : 'plain' } }) },
+                                ] });
+                            }}
+                        />
+                    </Form.Item>
+                </Col>}
+            </Row>}
+            {!!groupBy && !!groupBy.key && !scatterStyle.legendHidden && <Form.Item label='排布方向' {...formItemLayout}>
+                <Select
+                    defaultValue={scatterStyle.legendOrient || 'vertical'}
+                    onChange={(value, item) => {
+                        dispatch({ type: 'chartDesigner/setFields', fields: [
+                            { name: 'styleConfig', value: deepAssign(styleConfig, { scatter: { legendOrient: value } }) },
+                            { name: 'chartOption', value: deepAssign(chartOption, { legend: { orient: value } }) },
+                        ] });
+                    }}
+                >
+                    <Select.Option value='vertical'>纵向排布</Select.Option>
+                    <Select.Option value='horizontal'>横向排布</Select.Option>
+                </Select>
+            </Form.Item>}
+            {!!groupBy && !!groupBy.key && !scatterStyle.legendHidden && <Form.Item label='位置' {...formItemLayout}>
+                <Row>
+                    <Col span={8}>上边距:</Col>
+                    <Col span={16}>
+                        <Input
+                            defaultValue={scatterStyle.legendPosition ? scatterStyle.legendPosition['top'] : null}
+                            placeholder={50}
+                            onBlur={e => {
+                                let value = e.target.value;
+                                let legendHidden = scatterStyle.legendHidden,
+                                    legendOrient = scatterStyle.legendOrient || 'vertical',
+                                    legendTop = (value === '' || value === null || value === undefined) ? 50 : value,
+                                    legendBottom = scatterStyle.legendPosition ? scatterStyle.legendPosition.bottom || 50 : 50,
+                                    gridPositionTop = !legendHidden ? ( // 图例未隐藏
+                                        legendOrient === 'horizontal' ? ( // 图例排布方向为水平
+                                            legendTop === 'auto' ? ( // 已知图例上边距未设置
+                                                legendBottom === 'auto' ? 50 // 图例下边距也未设置,将靠上对齐,图域上边距保持50
+                                                : 50 // 图例下边距已设置
+                                            ) : ( // 图例上边距已设置
+                                                (legendTop + '').endsWith('%') ? (10 + Number(legendTop.replace('%', '')) + '%') // 图例上边距为百分比,图域上边距增加10%
+                                                : (50 + Number(legendTop))// 图例上边距为数字,图域上边距增加50
+                                            )
+                                        ) : 50
+                                    ) : 50 // 图例隐藏
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { scatter: { legendPosition: { top: value}, gridPosition: { top: gridPositionTop } } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { legend: {
+                                        top: legendTop,
+                                    }, grid: {
+                                        top: gridPositionTop
+                                    } }) },
+                                ] });
+                            }}
+                        />
+                    </Col>
+                </Row>
+                <Row>
+                    <Col span={8}>下边距:</Col>
+                    <Col span={16}>
+                        <Input
+                            defaultValue={scatterStyle.legendPosition ? scatterStyle.legendPosition['bottom'] : null}
+                            placeholder={50}
+                            onBlur={e => {
+                                let value = e.target.value;
+                                let legendHidden = scatterStyle.legendHidden,
+                                    legendOrient = scatterStyle.legendOrient || 'vertical',
+                                    legendTop = scatterStyle.legendPosition ? scatterStyle.legendPosition.top || 50 : 50,
+                                    legendBottom = (value === '' || value === null || value === undefined) ? 50 : value,
+                                    gridPositionBottom = !legendHidden ? ( // 图例未隐藏
+                                        legendOrient === 'horizontal' ? ( // 图例排布方向为水平
+                                            legendTop === 'auto' ? ( // 图例上边距未设置
+                                                legendBottom === 'auto' ? 50 // 已知图例下边距未设置
+                                                : ( // 图例下边距已设置
+                                                    (legendBottom + '').endsWith('%') ? (10 + Number(legendBottom.replace('%', '')) + '%') // 图例下边距为百分比,图域下边距增加10%
+                                                    : (50 + Number(legendBottom))// 图例下边距为数字,图域下边距增加50
+                                                )
+                                            ) : 50
+                                        ) : 50
+                                    ) : 50 // 图例隐藏
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { scatter: { legendPosition: { bottom: value}, gridPosition: { bottom: gridPositionBottom } } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { legend: {
+                                        bottom: legendBottom
+                                    }, grid: {
+                                        bottom: gridPositionBottom
+                                    } }) },
+                                ] });
+                            }}
+                        />
+                    </Col>
+                </Row>
+                <Row>
+                    <Col span={8}>左边距:</Col>
+                    <Col span={16}>
+                        <Input
+                            defaultValue={scatterStyle.legendPosition ? scatterStyle.legendPosition['left'] : null}
+                            placeholder='auto'
+                            onBlur={e => {
+                                let value = e.target.value;
+                                let legendHidden = scatterStyle.legendHidden,
+                                    legendOrient = scatterStyle.legendOrient || 'vertical',
+                                    legendLeft = (value === '' || value === null || value === undefined) ? 'auto' : value,
+                                    legendRight = scatterStyle.legendPosition ? scatterStyle.legendPosition.right || '5%' : '5%',
+                                    gridPositionLeft = !legendHidden ? ( // 图例未隐藏
+                                        legendOrient === 'vertical' ? ( // 图例排布方向为垂直
+                                            legendLeft === 'auto' ? ( // 已知图例左边距未设置
+                                                legendRight === 'auto' ? '10%' // 图例右边距也未设置,将靠左对齐,图域左边距增加
+                                                : '5%' // 图例右边距已设置
+                                            ) : ( // 图例左边距已设置
+                                                (legendLeft + '').endsWith('%') ? (10 + Number(legendLeft.replace('%', '')) + '%') // 图例左边距为百分比,图域左边距增加10%
+                                                : (100 + Number(legendLeft))// 图例左边距为数字,图域左边距增加100
+                                            )
+                                        ) : '5%'
+                                    ) : '5%' // 图例隐藏
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { scatter: { legendPosition: { left: value }, gridPosition: { left: gridPositionLeft } } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { legend: {
+                                        left: legendLeft
+                                    }, grid: {
+                                        left: gridPositionLeft
+                                    } }) },
+                                ] });
+                            }}
+                        />
+                    </Col>
+                </Row>
+                <Row>
+                    <Col span={8}>右边距:</Col>
+                    <Col span={16}>
+                        <Input
+                            defaultValue={scatterStyle.legendPosition ? scatterStyle.legendPosition['right'] : null}
+                            placeholder='5%'
+                            onBlur={e => {
+                                let value = e.target.value;
+                                let legendHidden = scatterStyle.legendHidden,
+                                    legendOrient = scatterStyle.legendOrient || 'vertical',
+                                    legendLeft = scatterStyle.legendPosition ? scatterStyle.legendPosition.left || 'auto' : 'auto',
+                                    legendRight = (value === '' || value === null || value === undefined) ? '5%' : value,
+                                    gridPositionRight = !legendHidden ? ( // 图例未隐藏
+                                        legendOrient === 'vertical' ? ( // 图例排布方向为垂直
+                                            legendLeft === 'auto' ? ( // 图例左边距未设置
+                                                legendRight === 'auto' ? '5%' // 已知图例右边距未设置
+                                                : ( // 图例右边距已设置
+                                                    (legendRight + '').endsWith('%') ? (10 + Number(legendRight.replace('%', '')) + '%') // 图例右边距为百分比,图域右边距增加10%
+                                                    : (100 + Number(legendRight))// 图例右边距为数字,图域右边距增加100
+                                                )
+                                            ) : '5%'
+                                        ) : '5%'
+                                    ) : '5%' // 图例隐藏
+                                dispatch({ type: 'chartDesigner/setFields', fields: [
+                                    { name: 'styleConfig', value: deepAssign(styleConfig, { scatter: { legendPosition: { right: value}, gridPosition: { right: gridPositionRight } } }) },
+                                    { name: 'chartOption', value: deepAssign(chartOption, { legend: {
+                                        right: legendRight
+                                    }, grid: {
+                                        right: gridPositionRight
+                                    } }) },
+                                ] });
+                            }}
+                        />
+                    </Col>
+                </Row>
+            </Form.Item>}
+        </Form>
+    }
+}
+
+export default connect(({ present: { chartDesigner } }) => ({ chartDesigner }))(ScatterStyle);

+ 2 - 1
src/components/chartDesigner/sections/style/theme.jsx

@@ -1,5 +1,5 @@
 import React from 'react'
-import { Collapse, Form, Select } from 'antd'
+import { Divider, Form, Select } from 'antd'
 import { connect } from 'dva'
 import themes from './theme/index'
 
@@ -20,6 +20,7 @@ class ThemeConfig extends React.Component {
         const { theme, chartOption } = chartDesigner;
 
         return <Form>
+            <Divider>主题</Divider>
             <Form.Item label='主题' {...formItemLayout}>
                 <Select
                     defaultValue={theme || 'default'}

+ 15 - 3
src/components/dashboardDesigner/viewLayout.jsx

@@ -1,7 +1,7 @@
 import React from "react"
 import "./viewLayout.less"
 import ReactGridLayout from 'react-grid-layout'
-import { Icon, Input } from 'antd'
+import { Modal, Icon, Input } from 'antd'
 import { connect } from 'dva'
 import ChartView from './chartView'
 import EmptyContent from '../common/emptyContent/index'
@@ -71,7 +71,7 @@ class ViewLayout extends React.PureComponent {
                         //     });
                         }}/> : <span>{name}</span>}
                         <div className='tools'>
-                            {editMode && (!editingKey || editingKey !== code) && <Icon type='edit' title='修改' style={{ cursor: 'pointer', marginLeft: '8px' }} onClick={() => {
+                            {editMode && (!editingKey || editingKey !== code) && !isPreview && <Icon type='edit' title='修改' style={{ cursor: 'pointer', marginLeft: '8px' }} onClick={() => {
                                 this.setState({
                                     editingKey: code,
                                     richTextReadOnly: true,
@@ -160,7 +160,7 @@ class ViewLayout extends React.PureComponent {
                     <EmptyContent />
                 </div> : children}
             </ReactGridLayout>
-            {visiblePreviewBox && <DataPreview
+            {visiblePreviewBox && previewItem.chartType === 'dataView' && <DataPreview
                 title={previewItem.name}
                 visibleBox={visiblePreviewBox}
                 hideBox={this.hidePreviewBox}
@@ -168,6 +168,18 @@ class ViewLayout extends React.PureComponent {
                     dispatch({ type: 'dashboardDesigner/fetchDataList', item: previewItem, mandatory: true, page, pageSize });
                 }}
             />}
+            {visiblePreviewBox && previewItem.chartType !== 'dataView' && <Modal
+                className='previewbox'
+                width='80%'
+                height='80%'
+                visible={visiblePreviewBox}
+                onCancel={this.hidePreviewBox}
+                footer={null}
+                keyboard={true}
+                maskClosable={true}
+                >
+                {!!previewItem && this.createElement(dashboardDesigner.items.find(item => item.code === previewItem.code), true, false)}
+            </Modal>}
         </div>);
     }
 }

+ 1 - 0
src/models/chart.js

@@ -298,6 +298,7 @@ export default {
                         data.scatterConfig = chartConfig;
                     }else if(viewType === 'aggregateTable') {
                         data.aggregateTableConfig = chartConfig;
+                        data.aggregateTableConfig.groupBy = [];
                     }else if(viewType === 'dataView') {
                         data.dataViewConfig = chartConfig;
                     }

+ 6 - 9
src/models/chartDesigner.js

@@ -58,10 +58,7 @@ export default {
             pieConfig: { xAxis: { column: {}, granularity: {} }, yAxis: { column: {}, gauge: {} }, threshold: 20 },
             scatterConfig: { xAxis: { column: {}, granularity: {} }, yAxis: { column: {}, gauge: {} }, groupBy: {key:''}, threshold: 1000 },
             theme: 'default',
-            styleConfig: {
-                aggregateTable: {},
-                pie: {},
-            },
+            styleConfig: {},
             otherConfig:{},
             description: '',
             filters: [],
@@ -366,7 +363,7 @@ export default {
                     timeout: 30000
                 });
                 if(!res.err && res.data.code > 0) {
-                    let option = parseChartOption('bar', res.data.data, barConfig, theme, styleConfig.bar);
+                    let option = parseChartOption('bar', res.data.data, barConfig, theme, styleConfig.bar || {});
                     yield put({ type: 'silentSetField', name: 'chartOption', value: option });
                 }else {
                     message.error('请求柱状图数据失败: ' + (res.err || res.data.msg));
@@ -441,7 +438,7 @@ export default {
                     timeout: 30000
                 });
                 if(!res.err && res.data.code > 0) {
-                    let option = parseChartOption('line', res.data.data, lineConfig, theme, styleConfig.line);
+                    let option = parseChartOption('line', res.data.data, lineConfig, theme, styleConfig.line || {});
                     yield put({ type: 'silentSetField', name: 'chartOption', value: option });
                 }else {
                     message.error('请求折线图数据失败: ' + (res.err || res.data.msg));
@@ -478,7 +475,7 @@ export default {
                     timeout: 30000
                 });
                 if(!res.err && res.data.code > 0) {
-                    let option = parseChartOption('scatter', res.data.data, scatterConfig, theme, styleConfig.scatter);
+                    let option = parseChartOption('scatter', res.data.data, scatterConfig, theme, styleConfig.scatter || {});
                     yield put({ type: 'silentSetField', name: 'chartOption', value: option });
                 }else {
                     message.error('请求散点图数据失败: ' + (res.err || res.data.msg));
@@ -528,7 +525,7 @@ export default {
         *fetchAggregateTableData(action, { select, call, put }) {
             try {
                 const chartDesigner = yield select(state => state.present.chartDesigner);
-                const { originData, code, aggregateTableConfig, filters, theme, styleConfig } = chartDesigner;
+                const { code, aggregateTableConfig, filters, theme, styleConfig } = chartDesigner;
                 const { targetColumn, statistics } = aggregateTableConfig;
 
                 const body = {
@@ -549,7 +546,7 @@ export default {
                     timeout: 30000
                 });
                 if(!res.err && res.data.code > 0) {
-                    let option = parseChartOption('aggregateTable', res.data.data, aggregateTableConfig, theme, styleConfig.aggregateTable || originData.styleConfig.aggregateTable);
+                    let option = parseChartOption('aggregateTable', res.data.data, aggregateTableConfig, theme, styleConfig.aggregateTable || {});
                     yield put({ type: 'silentSetField', name: 'chartOption', value: option });
                 }else {
                     message.error('请求统计数据失败: ' + (res.err || res.data.msg));

+ 4 - 3
src/models/dashboardDesigner.js

@@ -466,8 +466,8 @@ export default {
         *fetchChartData(action, { put, call, select }) {
             const { item, mandatory, page, pageSize } = action;
             const dashboardDesigner = yield select(state => state.present.dashboardDesigner);
-            const { creatorCode, filters, originData } = dashboardDesigner;
-            const { chartCode, theme, styleConfig } = item;
+            const { creatorCode, filters } = dashboardDesigner;
+            const { chartCode, theme } = item;
             
             if(!mandatory && !!item.chartOption) {
                 return false;
@@ -492,6 +492,7 @@ export default {
                 });
                 if(!res.err && res.data.code > 0) {
                     let resData = res.data.data;
+                    let styleConfig = resData.styleConfig ? JSON.parse(resData.styleConfig) || {} : {};
                     if(!resData) {
                         yield put({ type: 'setItemFields', code: chartCode, fields: [
                             { name: 'chartType', value: '' },
@@ -502,7 +503,7 @@ export default {
                     const { chartType : ctype, chartConfig: cfg } = resData.chartsColumnConfig;
                     const chartType = CHART_TYPE[ctype];
                     const chartConfig = JSON.parse(cfg);
-                    let chartOption = parseChartOption(chartType, resData, chartConfig, theme, styleConfig ? (styleConfig[chartType] || originData.styleConfig[chartType]) : {} );
+                    let chartOption = parseChartOption(chartType, resData, chartConfig, theme, styleConfig[chartType] || {});
                     
                     yield put({ type: 'setItemFields', code: chartCode, fields: [
                         { name: 'chartType', value: chartType },

+ 381 - 96
src/models/parseChartOption.js

@@ -56,10 +56,21 @@ export default function(viewType, data, chartConfig, themeName, styleConfig) {
 }
 
 function barOption(data, barConfig, themeConfig, styleConfig) {
-    let xTitle = barConfig.xAxis?`${barConfig.xAxis.column.label}${barConfig.xAxis.granularity.value?'('+barConfig.xAxis.granularity.label+')':''}`:null
-    let yTitle = barConfig.yAxis?`${barConfig.yAxis.column.label}${barConfig.yAxis.gauge.value?'('+barConfig.yAxis.gauge.label+')':''}`:null
+    const { xAxis, yAxis, groupBy } = barConfig;
+    const { gridPosition, barMaxWidth, barMinHeight, barGap, stack, labelVisible, labelPosition, labelDistance,
+        labelRotate, labelFormatter, xNameLocation, xNameGap, xNameRotate, xLabelHiddenCover, xLabelRotate,
+        xLabelMargin, yNameLocation, yNameGap, yNameRotate, legendHidden, legendInPagination,
+        legendOrient : styleLegendOrient, legendPosition, legendFormatter } = styleConfig;
+    let xTitle = xAxis?`${xAxis.column.label}${xAxis.granularity.value?'('+xAxis.granularity.label+')':''}`:null
+    let yTitle = yAxis?`${yAxis.column.label}${yAxis.gauge.value?'('+yAxis.gauge.label+')':''}`:null
     data.serieses = data.serieses || [];
 
+    let legendOrient = styleLegendOrient || 'vertical',
+        legendTop = legendPosition ? ((legendPosition.top === '' || legendPosition.top === null || legendPosition.top === undefined) ? 50 : legendPosition.top) : 50,
+        legendLeft = legendPosition ? ((legendPosition.left === '' || legendPosition.left === null || legendPosition.left === undefined) ? 'auto' : legendPosition.left) : 'auto',
+        legendRight = legendPosition ? ((legendPosition.right === '' || legendPosition.right === null || legendPosition.right === undefined) ? '10%' : legendPosition.right) : '10%',
+        legendBottom = legendPosition ? ((legendPosition.bottom === '' || legendPosition.bottom === null || legendPosition.bottom === undefined) ? 50 : legendPosition.bottom) : 50;
+
     let option = deepAssign({
         tooltip : {
             trigger: "axis",
@@ -71,19 +82,90 @@ function barOption(data, barConfig, themeConfig, styleConfig) {
             }
         },
         legend: {
-            show: data.serieses.length > 1
+            show: !!groupBy && !!groupBy.key && (legendHidden === undefined ? true : !legendHidden),
+            type: legendInPagination === undefined ? 'plain' : (!!legendInPagination ? 'scroll' : 'plain'),
+            orient: legendOrient,
+            top: legendTop,
+            left: legendLeft,
+            right: legendRight,
+            bottom: legendBottom,
+            formatter: legendFormatter || '{name}',
         },
         grid: {
-            left: '10%',
-            right: '10%',
-            top: 60,
-            bottom: 60,
+            top: (gridPosition && gridPosition.top && gridPosition.top !== 'auto') ? ( // 已设置图域上边距
+                gridPosition.top
+            ) : ( // 未设置图域上边距或设置自适应
+                (!legendHidden) ? ( // 图例未隐藏
+                    legendOrient === 'horizontal' ? ( // 图例排布方向为水平
+                        legendTop === 'auto' ? ( // 已知图例上边距未设置
+                            legendBottom === 'auto' ? 50 // 图例下边距也未设置,将靠上对齐,图域上边距保持50
+                            : 50 // 图例下边距已设置
+                        ) : ( // 图例上边距已设置
+                            (legendTop + '').endsWith('%') ? (10 + Number(legendTop.replace('%', '')) + '%') // 图例上边距为百分比,图域上边距增加10%
+                            : (50 + Number(legendTop))// 图例上边距为数字,图域上边距增加50
+                        )
+                    ) : 50 // 图例排布方向为垂直
+                ) : 50 // 图例隐藏
+            ),
+            left: (gridPosition && gridPosition.left && gridPosition.left !== 'auto') ? ( // 已设置图域左边距
+                gridPosition.left
+            ) : ( // 未设置图域左边距或设置自适应
+                (!legendHidden) ? ( // 图例未隐藏
+                    legendOrient === 'vartical' ? ( // 图例排布方向为垂直
+                        legendLeft === 'auto' ? ( // 已知图例左边距未设置
+                            legendRight === 'auto' ? '10%' // 图例右边距也未设置,将靠左对齐,图域左边距增加
+                            : '5%' // 图例右边距已设置
+                        ) : ( // 图例左边距已设置
+                            (legendLeft + '').endsWith('%') ? (10 + Number(legendLeft.replace('%', '')) + '%') // 图例左边距为百分比,图域左边距增加10%
+                            : (100 + Number(legendLeft))// 图例左边距为数字,图域左边距增加100
+                        )
+                    ) : '5%' // 图例排布方向为水平
+                ) : '5%' // 图例隐藏
+            ),
+            right: (gridPosition && gridPosition.right && gridPosition.right !== 'auto') ? ( // 已设置图域右边距
+                gridPosition.right
+            ) : ( // 未设置图域右边距或设置自适应
+                (!legendHidden) ? ( // 图例未隐藏
+                    legendOrient === 'vartical' ? ( //图例排布方向为垂直
+                        legendLeft === 'auto' ? ( // 图例左边距未设置
+                            legendRight === 'auto' ? '5%' // 已知图例右边距未设置
+                            : ( // 图例右边距已设置
+                                (legendRight + '').endsWith('%') ? (10 + Number(legendRight.replace('%', '')) + '%') // 图例右边距为百分比,图域右边距增加10%
+                                : (100 + Number(legendRight))// 图例右边距为数字,图域右边距增加100
+                            )
+                        ) : '5%'
+                    ) : '5%'
+                ) : '5%' // 图例隐藏
+            ),
+            bottom: (gridPosition && gridPosition.bottom && gridPosition.bottom !== 'auto') ? ( // 已设置图域下边距
+                gridPosition.bottom
+            ) : ( // 未设置图域下边距或设置自适应
+                (!legendHidden) ? ( // 图例未隐藏
+                    legendOrient === 'horizontal' ? ( //图例排布方向为水平
+                        legendTop === 'auto' ? ( // 图例上边距未设置
+                            legendBottom === 'auto' ? 50 // 已知图例下边距未设置
+                            : ( // 图例下边距已设置
+                                (legendBottom + '').endsWith('%') ? (10 + Number(legendBottom.replace('%', '')) + '%') // 图例下边距为百分比,图域下边距增加10%
+                                : (50 + Number(legendBottom))// 图例下边距为数字,图域下边距增加50
+                            )
+                        ) : 50
+                    ) : 50
+                ) : 50 // 图例隐藏
+            ),
             containLabel: true
         },
         xAxis: [{
             type: 'category',
+            nameLocation: (xNameLocation === '' || xNameLocation === null || xNameLocation === undefined) ? 'end' : xNameLocation,
+            nameGap: (xNameGap === '' || xNameGap === null || xNameGap === undefined) ? 15 : Number(xNameGap),
+            nameRotate: (xNameRotate === '' || xNameRotate === null || xNameRotate === undefined) ? 0 : Number(xNameRotate),
+            axisLabel: {
+                interval: xLabelHiddenCover === undefined ? 'auto' : (!!xLabelHiddenCover ? 'auto' : 0),
+                rotate: (xLabelRotate === '' || xLabelRotate === null || xLabelRotate === undefined) ? 0 : Number(xLabelRotate),
+                margin: (xLabelMargin === '' || xLabelMargin === null || xLabelMargin === undefined) ? 8 : Number(xLabelMargin),
+            },
             data: data.xAxis.map(d => {
-                let gv= barConfig.xAxis.granularity.value;
+                let gv= xAxis.granularity.value;
                 let xv = d || '空';
                 if(gv === 'halfYear') {
                     let arr = d.split('-H');
@@ -103,24 +185,184 @@ function barOption(data, barConfig, themeConfig, styleConfig) {
         }],
         yAxis: [{
             name: yTitle || '纵轴',
-            type: 'value'
+            type: 'value',
+            nameLocation: (yNameLocation === '' || yNameLocation === null || yNameLocation === undefined) ? 'end' : yNameLocation,
+            nameGap: (yNameGap === '' || yNameGap === null || yNameGap === undefined) ? 15 : Number(yNameGap),
+            nameRotate: (yNameRotate === '' || yNameRotate === null || yNameRotate === undefined) ? 0 : Number(yNameRotate),
         }],
         series: data.serieses.map(s => {
             return {
-                name: barConfig.groupBy ? s.name : (barConfig.yAxis.column.label || s.name),
+                name: groupBy ? s.name : (yAxis.column.label || s.name),
                 type: 'bar',
                 data: s.value,
-                // stack: s.stack
+                barMaxWidth: barMaxWidth || '50%',
+                barMinHeight: barMinHeight || 0,
+                barGap: barGap || '30%',
+                stack: !!groupBy && !!groupBy.key && !!stack,
+                label: {
+                    normal: {
+                        show: !!labelVisible,
+                        position: labelPosition || 'inside',
+                        distance: (labelDistance === '' || labelDistance === null || labelDistance === undefined) ? 5 : Number(labelDistance),
+                        rotate: (labelRotate === '' || labelRotate === null || labelRotate === undefined) ? 0 : Number(labelRotate),
+                        formatter: (labelFormatter === '' || labelFormatter === null || labelFormatter === undefined) ? '{c}' : labelFormatter,
+                    }
+                }
             }
         }),
         dataZoom: {
             show: false
         }
-    }, themeConfig, styleConfig);
+    }, themeConfig);
     
     return option;
 }
 
+function lineOption(data, lineConfig, themeConfig, styleConfig) {
+    const { gridPosition, legendHidden, legendInPagination, legendOrient : styleLegendOrient, legendPosition, labelSymbol,
+        legendFormatter, xNameLocation, xNameGap, xNameRotate, xLabelRotate, xLabelMargin,
+        yNameLocation, yNameGap, yNameRotate, stack, labelVisible, labelPosition, labelDistance, labelRotate,
+        labelFormatter, lineSmooth, labelSymbolSize } = styleConfig;
+    const { xAxis, yAxis, groupBy } = lineConfig;
+    let xTitle = xAxis?`${xAxis.column.label}${xAxis.granularity.value?'('+xAxis.granularity.label+')':''}`:null
+    let yTitle = yAxis?`${yAxis.column.label}${yAxis.gauge.value?'('+yAxis.gauge.label+')':''}`:null
+    data.serieses = data.serieses || [];
+
+    let legendOrient = styleLegendOrient || 'vertical',
+        legendTop = legendPosition ? ((legendPosition.top === '' || legendPosition.top === null || legendPosition.top === undefined) ? 50 : legendPosition.top) : 50,
+        legendLeft = legendPosition ? ((legendPosition.left === '' || legendPosition.left === null || legendPosition.left === undefined) ? 'auto' : legendPosition.left) : 'auto',
+        legendRight = legendPosition ? ((legendPosition.right === '' || legendPosition.right === null || legendPosition.right === undefined) ? '10%' : legendPosition.right) : '10%',
+        legendBottom = legendPosition ? ((legendPosition.bottom === '' || legendPosition.bottom === null || legendPosition.bottom === undefined) ? 50 : legendPosition.bottom) : 50;
+
+    let option = deepAssign({
+        grid: {
+            top: (gridPosition && gridPosition.top && gridPosition.top !== 'auto') ? ( // 已设置图域上边距
+                gridPosition.top
+            ) : ( // 未设置图域上边距或设置自适应
+                (!legendHidden) ? ( // 图例未隐藏
+                    legendOrient === 'horizontal' ? ( // 图例排布方向为水平
+                        legendTop === 'auto' ? ( // 已知图例上边距未设置
+                            legendBottom === 'auto' ? 50 // 图例下边距也未设置,将靠上对齐,图域上边距保持50
+                            : 50 // 图例下边距已设置
+                        ) : ( // 图例上边距已设置
+                            (legendTop + '').endsWith('%') ? (10 + Number(legendTop.replace('%', '')) + '%') // 图例上边距为百分比,图域上边距增加10%
+                            : (50 + Number(legendTop))// 图例上边距为数字,图域上边距增加50
+                        )
+                    ) : 50 // 图例排布方向为垂直
+                ) : 50 // 图例隐藏
+            ),
+            left: (gridPosition && gridPosition.left && gridPosition.left !== 'auto') ? ( // 已设置图域左边距
+                gridPosition.left
+            ) : ( // 未设置图域左边距或设置自适应
+                (!legendHidden) ? ( // 图例未隐藏
+                    legendOrient === 'vartical' ? ( // 图例排布方向为垂直
+                        legendLeft === 'auto' ? ( // 已知图例左边距未设置
+                            legendRight === 'auto' ? '10%' // 图例右边距也未设置,将靠左对齐,图域左边距增加
+                            : '5%' // 图例右边距已设置
+                        ) : ( // 图例左边距已设置
+                            (legendLeft + '').endsWith('%') ? (10 + Number(legendLeft.replace('%', '')) + '%') // 图例左边距为百分比,图域左边距增加10%
+                            : (100 + Number(legendLeft))// 图例左边距为数字,图域左边距增加100
+                        )
+                    ) : '5%' // 图例排布方向为水平
+                ) : '5%' // 图例隐藏
+            ),
+            right: (gridPosition && gridPosition.right && gridPosition.right !== 'auto') ? ( // 已设置图域右边距
+                gridPosition.right
+            ) : ( // 未设置图域右边距或设置自适应
+                (!legendHidden) ? ( // 图例未隐藏
+                    legendOrient === 'vartical' ? ( //图例排布方向为垂直
+                        legendLeft === 'auto' ? ( // 图例左边距未设置
+                            legendRight === 'auto' ? '5%' // 已知图例右边距未设置
+                            : ( // 图例右边距已设置
+                                (legendRight + '').endsWith('%') ? (10 + Number(legendRight.replace('%', '')) + '%') // 图例右边距为百分比,图域右边距增加10%
+                                : (100 + Number(legendRight))// 图例右边距为数字,图域右边距增加100
+                            )
+                        ) : '5%'
+                    ) : '5%'
+                ) : '5%' // 图例隐藏
+            ),
+            bottom: (gridPosition && gridPosition.bottom && gridPosition.bottom !== 'auto') ? ( // 已设置图域下边距
+                gridPosition.bottom
+            ) : ( // 未设置图域下边距或设置自适应
+                (!legendHidden) ? ( // 图例未隐藏
+                    legendOrient === 'horizontal' ? ( //图例排布方向为水平
+                        legendTop === 'auto' ? ( // 图例上边距未设置
+                            legendBottom === 'auto' ? 50 // 已知图例下边距未设置
+                            : ( // 图例下边距已设置
+                                (legendBottom + '').endsWith('%') ? (10 + Number(legendBottom.replace('%', '')) + '%') // 图例下边距为百分比,图域下边距增加10%
+                                : (50 + Number(legendBottom))// 图例下边距为数字,图域下边距增加50
+                            )
+                        ) : 50
+                    ) : 50
+                ) : 50 // 图例隐藏
+            ),
+            containLabel: true
+        },
+        tooltip: {
+            trigger: 'axis',
+            axisPointer: {
+                type: 'cross'
+            }
+        },
+        legend: {
+            show: !!groupBy && !!groupBy.key && (legendHidden === undefined ? true : !legendHidden),
+            type: legendInPagination === undefined ? 'plain' : (!!legendInPagination ? 'scroll' : 'plain'),
+            orient: legendOrient,
+            top: legendTop,
+            left: legendLeft,
+            right: legendRight,
+            bottom: legendBottom,
+            formatter: legendFormatter || '{name}',
+        },
+        xAxis:  [{
+            name: xTitle || '横轴',
+            type: 'time',
+            nameLocation: (xNameLocation === '' || xNameLocation === null || xNameLocation === undefined) ? 'end' : xNameLocation,
+            nameGap: (xNameGap === '' || xNameGap === null || xNameGap === undefined) ? 15 : Number(xNameGap),
+            nameRotate: (xNameRotate === '' || xNameRotate === null || xNameRotate === undefined) ? 0 : Number(xNameRotate),
+            axisLabel: {
+                rotate: (xLabelRotate === '' || xLabelRotate === null || xLabelRotate === undefined) ? 0 : Number(xLabelRotate),
+                margin: (xLabelMargin === '' || xLabelMargin === null || xLabelMargin === undefined) ? 8 : Number(xLabelMargin),
+            },
+        }],
+        yAxis: [{
+            name: yTitle || '纵轴',
+            type: 'value',
+            nameLocation: (yNameLocation === '' || yNameLocation === null || yNameLocation === undefined) ? 'end' : yNameLocation,
+            nameGap: (yNameGap === '' || yNameGap === null || yNameGap === undefined) ? 15 : Number(yNameGap),
+            nameRotate: (yNameRotate === '' || yNameRotate === null || yNameRotate === undefined) ? 0 : Number(yNameRotate),
+        }],
+        
+        series: (data.serieses || []).map(s => {
+            return {
+                name: s.name,
+                type: 'line',
+                stack: !!groupBy && !!groupBy.key && !!stack,
+                label: {
+                    normal: {
+                        show: !!labelVisible,
+                        position: labelPosition || 'inside',
+                        distance: (labelDistance === '' || labelDistance === null || labelDistance === undefined) ? 5 : Number(labelDistance),
+                        rotate: (labelRotate === '' || labelRotate === null || labelRotate === undefined) ? 0 : Number(labelRotate),
+                        formatter: (labelFormatter === '' || labelFormatter === null || labelFormatter === undefined) ? '{c}' : labelFormatter,
+                    },
+                },
+                symbol: !labelSymbol ? 'emptyCircle' : labelSymbol,
+                symbolSize: (labelSymbolSize === '' || labelSymbolSize === null || labelSymbolSize === undefined) ? 4 : Number(labelSymbolSize),
+                smooth: !!lineSmooth,
+                data: s.mdata.map(m => {
+                    return [m.date, m.value]
+                }).sort((a, b) => {return new Date(a[0]).getTime() - new Date(b[0]).getTime()} )
+            }
+        }),
+        dataZoom: {
+            show: false
+        }
+    }, themeConfig, styleConfig);
+
+    return option;
+}
+
 function pieOption(data, pieConfig, themeConfig, styleConfig) {
     let columnName = pieConfig.xAxis.column.label + (pieConfig.xAxis.granularity.value ? '('+pieConfig.xAxis.granularity.label+')' : '');
     const { pieCenter, pieRadius, legendHidden, legendInPagination, legendOrient, legendPosition, legendFormatter,
@@ -142,22 +384,24 @@ function pieOption(data, pieConfig, themeConfig, styleConfig) {
             formatter: legendFormatter || '{name}',
             data: data.xAxis.map(d => {
                 let gv= pieConfig.xAxis.granularity.value;
-                let xv;
+                let xv = d;
                 if(!d) {
-                    return '空';
-                }
-                if(gv === 'halfYear') {
-                    let arr = d.split('-H');
-                    xv = arr[0] + ['上半年', '下半年'][arr[1] - 1]
-                }else if(gv === 'month') {
-                    xv = d.replace('-M', '-');
-                }else if(gv === 'quarter') {
-                    let arr = d.split('-Q');
-                    xv = arr[0] + '-' + ['一', '二', '三', '四'][arr[1] - 1] + '季度'
-                }else if(gv === 'week') {
-                    let arr = d.split('-W');
-                    xv = arr[0] + '-' + arr[1] + '周'
+                    xv = '空';
+                }else {
+                    if(gv === 'halfYear') {
+                        let arr = d.split('-H');
+                        xv = arr[0] + ['上半年', '下半年'][arr[1] - 1]
+                    }else if(gv === 'month') {
+                        xv = d.replace('-M', '-');
+                    }else if(gv === 'quarter') {
+                        let arr = d.split('-Q');
+                        xv = arr[0] + '-' + ['一', '二', '三', '四'][arr[1] - 1] + '季度'
+                    }else if(gv === 'week') {
+                        let arr = d.split('-W');
+                        xv = arr[0] + '-' + arr[1] + '周'
+                    }
                 }
+                
                 return xv;
             }),
         },
@@ -226,12 +470,82 @@ function pieOption(data, pieConfig, themeConfig, styleConfig) {
     return option;
 }
 
-function lineOption(data, lineConfig, themeConfig, styleConfig) {
-    let xTitle = lineConfig.xAxis?`${lineConfig.xAxis.column.label}${lineConfig.xAxis.granularity.value?'('+lineConfig.xAxis.granularity.label+')':''}`:null
-    let yTitle = lineConfig.yAxis?`${lineConfig.yAxis.column.label}${lineConfig.yAxis.gauge.value?'('+lineConfig.yAxis.gauge.label+')':''}`:null
-    data.serieses = data.serieses || [];
-
+function scatterOption(data, scatterConfig, themeConfig, styleConfig) {
+    const { gridPosition, legendHidden, legendInPagination, legendOrient : styleLegendOrient, legendPosition,
+        labelSymbol, legendFormatter, xNameLocation, xNameGap, xNameRotate, xLabelRotate, xLabelMargin,
+        yNameLocation, yNameGap, yNameRotate, labelSymbolSize, xLabelHiddenCover } = styleConfig;
+    let xTitle = scatterConfig.xAxis?`${scatterConfig.xAxis.column.label}${scatterConfig.xAxis.granularity.value?'('+scatterConfig.xAxis.granularity.label+')':''}`:null
+    let yTitle = scatterConfig.yAxis?`${scatterConfig.yAxis.column.label}${scatterConfig.yAxis.gauge.value?'('+scatterConfig.yAxis.gauge.label+')':''}`:null
+    
+    let legendOrient = styleLegendOrient || 'vertical',
+        legendTop = legendPosition ? ((legendPosition.top === '' || legendPosition.top === null || legendPosition.top === undefined) ? 50 : legendPosition.top) : 50,
+        legendLeft = legendPosition ? ((legendPosition.left === '' || legendPosition.left === null || legendPosition.left === undefined) ? 'auto' : legendPosition.left) : 'auto',
+        legendRight = legendPosition ? ((legendPosition.right === '' || legendPosition.right === null || legendPosition.right === undefined) ? '10%' : legendPosition.right) : '10%',
+        legendBottom = legendPosition ? ((legendPosition.bottom === '' || legendPosition.bottom === null || legendPosition.bottom === undefined) ? 50 : legendPosition.bottom) : 50;
     let option = deepAssign({
+        grid: {
+            top: (gridPosition && gridPosition.top && gridPosition.top !== 'auto') ? ( // 已设置图域上边距
+                gridPosition.top
+            ) : ( // 未设置图域上边距或设置自适应
+                (!legendHidden) ? ( // 图例未隐藏
+                    legendOrient === 'horizontal' ? ( // 图例排布方向为水平
+                        legendTop === 'auto' ? ( // 已知图例上边距未设置
+                            legendBottom === 'auto' ? 50 // 图例下边距也未设置,将靠上对齐,图域上边距保持50
+                            : 50 // 图例下边距已设置
+                        ) : ( // 图例上边距已设置
+                            (legendTop + '').endsWith('%') ? (10 + Number(legendTop.replace('%', '')) + '%') // 图例上边距为百分比,图域上边距增加10%
+                            : (50 + Number(legendTop))// 图例上边距为数字,图域上边距增加50
+                        )
+                    ) : 50 // 图例排布方向为垂直
+                ) : 50 // 图例隐藏
+            ),
+            left: (gridPosition && gridPosition.left && gridPosition.left !== 'auto') ? ( // 已设置图域左边距
+                gridPosition.left
+            ) : ( // 未设置图域左边距或设置自适应
+                (!legendHidden) ? ( // 图例未隐藏
+                    legendOrient === 'vartical' ? ( // 图例排布方向为垂直
+                        legendLeft === 'auto' ? ( // 已知图例左边距未设置
+                            legendRight === 'auto' ? '10%' // 图例右边距也未设置,将靠左对齐,图域左边距增加
+                            : '5%' // 图例右边距已设置
+                        ) : ( // 图例左边距已设置
+                            (legendLeft + '').endsWith('%') ? (10 + Number(legendLeft.replace('%', '')) + '%') // 图例左边距为百分比,图域左边距增加10%
+                            : (100 + Number(legendLeft))// 图例左边距为数字,图域左边距增加100
+                        )
+                    ) : '5%' // 图例排布方向为水平
+                ) : '5%' // 图例隐藏
+            ),
+            right: (gridPosition && gridPosition.right && gridPosition.right !== 'auto') ? ( // 已设置图域右边距
+                gridPosition.right
+            ) : ( // 未设置图域右边距或设置自适应
+                (!legendHidden) ? ( // 图例未隐藏
+                    legendOrient === 'vartical' ? ( //图例排布方向为垂直
+                        legendLeft === 'auto' ? ( // 图例左边距未设置
+                            legendRight === 'auto' ? '5%' // 已知图例右边距未设置
+                            : ( // 图例右边距已设置
+                                (legendRight + '').endsWith('%') ? (10 + Number(legendRight.replace('%', '')) + '%') // 图例右边距为百分比,图域右边距增加10%
+                                : (100 + Number(legendRight))// 图例右边距为数字,图域右边距增加100
+                            )
+                        ) : '5%'
+                    ) : '5%'
+                ) : '5%' // 图例隐藏
+            ),
+            bottom: (gridPosition && gridPosition.bottom && gridPosition.bottom !== 'auto') ? ( // 已设置图域下边距
+                gridPosition.bottom
+            ) : ( // 未设置图域下边距或设置自适应
+                (!legendHidden) ? ( // 图例未隐藏
+                    legendOrient === 'horizontal' ? ( //图例排布方向为水平
+                        legendTop === 'auto' ? ( // 图例上边距未设置
+                            legendBottom === 'auto' ? 50 // 已知图例下边距未设置
+                            : ( // 图例下边距已设置
+                                (legendBottom + '').endsWith('%') ? (10 + Number(legendBottom.replace('%', '')) + '%') // 图例下边距为百分比,图域下边距增加10%
+                                : (50 + Number(legendBottom))// 图例下边距为数字,图域下边距增加50
+                            )
+                        ) : 50
+                    ) : 50
+                ) : 50 // 图例隐藏
+            ),
+            containLabel: true
+        },
         tooltip: {
             trigger: 'axis',
             axisPointer: {
@@ -239,77 +553,48 @@ function lineOption(data, lineConfig, themeConfig, styleConfig) {
             }
         },
         legend: {
-            show: data.serieses.length > 1
+            show: legendHidden === undefined ? true : !legendHidden,
+            type: legendInPagination === undefined ? 'plain' : (!!legendInPagination ? 'scroll' : 'plain'),
+            orient: legendOrient || 'vertical',
+            top: legendPosition ? legendPosition.top || 50 : 50,
+            left: legendPosition ? legendPosition.left || 'auto' : 'auto',
+            right: legendPosition ? legendPosition.right || '10%' : '10%',
+            bottom: legendPosition ? legendPosition.bottom || 50 : 50,
+            formatter: legendFormatter || '{name}'
         },
-        xAxis:  {
+        xAxis : [{
+            type : 'value',
             name: xTitle || '横轴',
-            type: 'time'
-        },
-        yAxis: {
-            name: yTitle || '纵轴',
-            type: 'value'
-        },
-        
-        series: (data.serieses || []).map(s => {
-            return {
-                name: s.name,
-                type: 'line',
-                data: s.mdata.map(m => {
-                    return [m.date, m.value]
-                }).sort((a, b) => {return new Date(a[0]).getTime() - new Date(b[0]).getTime()} )
-            }
-        }),
-        dataZoom: {
-            show: false
-        }
-    }, themeConfig, styleConfig);
-
-    return option;
-}
-
-function scatterOption(data, scatterConfig, themeConfig, styleConfig) {
-    let xTitle = scatterConfig.xAxis?`${scatterConfig.xAxis.column.label}${scatterConfig.xAxis.granularity.value?'('+scatterConfig.xAxis.granularity.label+')':''}`:null
-    let yTitle = scatterConfig.yAxis?`${scatterConfig.yAxis.column.label}${scatterConfig.yAxis.gauge.value?'('+scatterConfig.yAxis.gauge.label+')':''}`:null
-    
-    let option = deepAssign({
-        tooltip : {
-            showDelay : 0,
-            axisPointer:{
-                show: true,
-                type : 'cross',
-                lineStyle: {
-                    type : 'dashed',
-                    width : 1
-                }
-            }
-        },
-        legend: {
-            show: true
-        },
-        xAxis : [
-            {
-                type : 'value',
-                name: xTitle || '横轴',
-                scale:true,
-                splitLine: {
-                    show: true
-                }
+            nameLocation: (xNameLocation === '' || xNameLocation === null || xNameLocation === undefined) ? 'end' : xNameLocation,
+            nameGap: (xNameGap === '' || xNameGap === null || xNameGap === undefined) ? 15 : Number(xNameGap),
+            nameRotate: (xNameRotate === '' || xNameRotate === null || xNameRotate === undefined) ? 0 : Number(xNameRotate),
+            axisLabel: {
+                interval: xLabelHiddenCover === undefined ? 'auto' : (!!xLabelHiddenCover ? 'auto' : 0),
+                rotate: (xLabelRotate === '' || xLabelRotate === null || xLabelRotate === undefined) ? 0 : Number(xLabelRotate),
+                margin: (xLabelMargin === '' || xLabelMargin === null || xLabelMargin === undefined) ? 8 : Number(xLabelMargin),
+            },
+            scale:true,
+            splitLine: {
+                show: true
             }
-        ],
-        yAxis : [
-            {
-                type : 'value',
-                name: yTitle || '纵轴',
-                scale:true,
-                splitLine: {
-                    show: true
-                }
-            }
-        ],
+        }],
+        yAxis : [{
+            type : 'value',
+            name: yTitle || '纵轴',
+            nameLocation: (yNameLocation === '' || yNameLocation === null || yNameLocation === undefined) ? 'end' : yNameLocation,
+            nameGap: (yNameGap === '' || yNameGap === null || yNameGap === undefined) ? 15 : Number(yNameGap),
+            nameRotate: (yNameRotate === '' || yNameRotate === null || yNameRotate === undefined) ? 0 : Number(yNameRotate),
+            scale:true,
+            splitLine: {
+                show: true
+            },
+        }],
         series : (data.serieses || []).map(s => {
             return {
                 name: s.name,
                 type: 'scatter',
+                symbol: !labelSymbol ? 'circle' : labelSymbol,
+                symbolSize: (labelSymbolSize === '' || labelSymbolSize === null || labelSymbolSize === undefined) ? 10 : Number(labelSymbolSize),
                 data: s.mdata.map(m => {
                     return [m.date, m.value]
                 })
@@ -318,7 +603,7 @@ function scatterOption(data, scatterConfig, themeConfig, styleConfig) {
         dataZoom: {
             show: false
         }
-    }, themeConfig, styleConfig);
+    }, themeConfig);
 
     return option;
 }

+ 1 - 1
src/themes/default/chartdesigner.less

@@ -43,7 +43,7 @@
                                     background: @tab-bg-color-active;
                                 }
                             }
-                            .ant-form-item, .ant-form-item-label > label {
+                            .ant-divider, .ant-form-item, .ant-form-item-label > label {
                                 color: @text-color;
                             }
                             .checkbox-group-statistics {