From c148b6414534e7e1b0d08ada36a3da9638fb334e Mon Sep 17 00:00:00 2001 From: niko <644506165@qq.com> Date: Fri, 29 Dec 2017 13:49:19 +0800 Subject: [PATCH] Upgrade BizCharts (#370) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update bizcharts * fixed lint * add charts autoHeight decorator * 升级 TimelineChart * 升级 TagCloud * upgrade bizcharts-plugin-slider * fix(chart): tag cloud overlapping (#461) The key point is: `chart.coord().reflect()`. and you can adjust gaps between words by setting padding for tag-cloud transform * upgrade react@16 & bizcharts@3.1.0 * update bizcharts to 3.1.0-beta2 * fix bizcharts repaint * upgrade to bizcharts@3.1.0-beta.4 * fix TimelineCharts detail style --- .gitignore | 1 + .roadhogrc | 5 - package.json | 6 +- src/components/ActiveChart/index.js | 51 ++- src/components/Charts/Bar/index.d.ts | 2 +- src/components/Charts/Bar/index.js | 128 ++----- src/components/Charts/Gauge/index.js | 345 ++++++++---------- src/components/Charts/MiniArea/index.js | 164 ++++----- src/components/Charts/MiniBar/index.js | 95 ++--- src/components/Charts/Pie/index.d.ts | 2 +- src/components/Charts/Pie/index.js | 285 +++++++-------- src/components/Charts/Radar/index.d.ts | 2 +- src/components/Charts/Radar/index.js | 265 +++++++------- src/components/Charts/TagCloud/index.js | 200 +++++----- .../Charts/TimelineChart/index.d.ts | 1 + src/components/Charts/TimelineChart/index.js | 208 ++++++----- src/components/Charts/WaterWave/index.js | 47 ++- src/components/Charts/autoHeight.js | 63 ++++ src/components/Charts/equal.js | 17 - src/g2.js | 26 +- src/index.ejs | 6 +- src/index.less | 8 +- src/routes/Dashboard/Analysis.js | 183 +++++----- src/routes/Dashboard/Monitor.js | 34 +- 24 files changed, 977 insertions(+), 1167 deletions(-) create mode 100644 src/components/Charts/autoHeight.js delete mode 100644 src/components/Charts/equal.js diff --git a/.gitignore b/.gitignore index aeab0079..aecc7945 100755 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ _roadhog-api-doc npm-debug.log* /coverage +.idea diff --git a/.roadhogrc b/.roadhogrc index 4fd3e119..10b47806 100755 --- a/.roadhogrc +++ b/.roadhogrc @@ -13,11 +13,6 @@ ] } }, - "externals": { - "g2": "G2", - "g-cloud": "Cloud", - "g2-plugin-slider": "G2.Plugin.slider" - }, "ignoreMomentLocale": true, "theme": "./src/theme.js", "hash": true diff --git a/package.json b/package.json index 723f5165..409515b2 100755 --- a/package.json +++ b/package.json @@ -19,17 +19,17 @@ "test:all": "node ./tests/run-tests.js" }, "dependencies": { + "@antv/data-set": "^0.8.0", "antd": "^3.0.0", "babel-polyfill": "^6.26.0", "babel-runtime": "^6.9.2", + "bizcharts": "^3.1.0-beta.4", + "bizcharts-plugin-slider": "^2.0.1", "classnames": "^2.2.5", "core-js": "^2.5.1", "dva": "^2.1.0", "enquire-js": "^0.1.1", "fastclick": "^1.0.6", - "g-cloud": "^1.0.2-beta", - "g2": "^2.3.13", - "g2-plugin-slider": "^1.2.1", "lodash": "^4.17.4", "lodash-decorators": "^4.4.1", "lodash.clonedeep": "^4.5.0", diff --git a/src/components/ActiveChart/index.js b/src/components/ActiveChart/index.js index 3b8e80dd..d708641c 100644 --- a/src/components/ActiveChart/index.js +++ b/src/components/ActiveChart/index.js @@ -1,4 +1,4 @@ -import React, { PureComponent } from 'react'; +import React, { Component } from 'react'; import { MiniArea } from '../Charts'; import NumberInfo from '../NumberInfo'; @@ -14,16 +14,16 @@ function getActiveData() { for (let i = 0; i < 24; i += 1) { activeData.push({ x: `${fixedZero(i)}:00`, - y: (i * 50) + (Math.floor(Math.random() * 200)), + y: Math.floor(Math.random() * 200) + (i * 50), }); } return activeData; } -export default class ActiveChart extends PureComponent { +export default class ActiveChart extends Component { state = { activeData: getActiveData(), - } + }; componentDidMount() { this.timer = setInterval(() => { @@ -42,43 +42,40 @@ export default class ActiveChart extends PureComponent { return (
- +
- { - activeData && ( -
-

{[...activeData].sort()[activeData.length - 1].y + 200} 亿元

-

{[...activeData].sort()[Math.floor(activeData.length / 2)].y} 亿元

-
- ) - } - { - activeData && ( -
- 00:00 - {activeData[Math.floor(activeData.length / 2)].x} - {activeData[activeData.length - 1].x} -
- ) - } + {activeData && ( +
+

{[...activeData].sort()[activeData.length - 1].y + 200} 亿元

+

{[...activeData].sort()[Math.floor(activeData.length / 2)].y} 亿元

+
+ )} + {activeData && ( +
+ 00:00 + {activeData[Math.floor(activeData.length / 2)].x} + {activeData[activeData.length - 1].x} +
+ )}
); } diff --git a/src/components/Charts/Bar/index.d.ts b/src/components/Charts/Bar/index.d.ts index fd2d05de..b79630ab 100644 --- a/src/components/Charts/Bar/index.d.ts +++ b/src/components/Charts/Bar/index.d.ts @@ -2,7 +2,7 @@ import * as React from "react"; export interface BarProps { title: React.ReactNode; color?: string; - margin?: [number, number, number, number]; + padding?: [number, number, number, number]; height: number; data: Array<{ x: string; diff --git a/src/components/Charts/Bar/index.js b/src/components/Charts/Bar/index.js index ef834d1c..c63bc92b 100644 --- a/src/components/Charts/Bar/index.js +++ b/src/components/Charts/Bar/index.js @@ -1,37 +1,26 @@ -import React, { PureComponent } from 'react'; -import G2 from 'g2'; +import React, { Component } from 'react'; +import { Chart, Axis, Tooltip, Geom } from 'bizcharts'; import Debounce from 'lodash-decorators/debounce'; import Bind from 'lodash-decorators/bind'; -import equal from '../equal'; +import autoHeight from '../autoHeight'; import styles from '../index.less'; -class Bar extends PureComponent { +@autoHeight() +class Bar extends Component { state = { autoHideXLabels: false, - } + }; componentDidMount() { - this.renderChart(this.props.data); - window.addEventListener('resize', this.resize); } - componentWillReceiveProps(nextProps) { - if (!equal(this.props, nextProps)) { - this.renderChart(nextProps.data); - } - } - componentWillUnmount() { window.removeEventListener('resize', this.resize); - if (this.chart) { - this.chart.destroy(); - } - this.resize.cancel(); } @Bind() - @Debounce(200) + @Debounce(400) resize() { if (!this.node) { return; @@ -49,99 +38,60 @@ class Bar extends PureComponent { this.setState({ autoHideXLabels: true, }); - this.renderChart(data); } } else if (autoHideXLabels) { this.setState({ autoHideXLabels: false, }); - this.renderChart(data); } } + handleRoot = (n) => { + this.root = n; + }; + handleRef = (n) => { this.node = n; - } - - renderChart(data) { - const { autoHideXLabels } = this.state; - const { - height = 0, - fit = true, - color = 'rgba(24, 144, 255, 0.85)', - margin = [32, 0, (autoHideXLabels ? 8 : 32), 40], - } = this.props; - - - if (!data || (data && data.length < 1)) { - return; - } + }; - // clean - this.node.innerHTML = ''; - - const { Frame } = G2; - const frame = new Frame(data); - - const chart = new G2.Chart({ - container: this.node, - forceFit: fit, - height: height - 22, - legend: null, - plotCfg: { - margin, - }, - }); + render() { + const { height, title, forceFit = true, data, color = 'rgba(24, 144, 255, 0.85)', padding } = this.props; - if (autoHideXLabels) { - chart.axis('x', { - title: false, - tickLine: false, - labels: false, - }); - } else { - chart.axis('x', { - title: false, - }); - } - chart.axis('y', { - title: false, - line: false, - tickLine: false, - }); + const { autoHideXLabels } = this.state; - chart.source(frame, { + const scale = { x: { type: 'cat', }, y: { min: 0, }, - }); - - chart.tooltip({ - title: null, - crosshairs: false, - map: { - name: 'x', - }, - }); - chart.interval().position('x*y').color(color).style({ - fillOpacity: 1, - }); - chart.render(); + }; - this.chart = chart; - } - - render() { - const { height, title } = this.props; + const tooltip = [ + 'x*y', + (x, y) => ({ + name: x, + value: y, + }), + ]; return ( -
-
- { title &&

{title}

} -
+
+
+ {title &&

{title}

} + + + + + +
); diff --git a/src/components/Charts/Gauge/index.js b/src/components/Charts/Gauge/index.js index cba42020..608b0f2e 100644 --- a/src/components/Charts/Gauge/index.js +++ b/src/components/Charts/Gauge/index.js @@ -1,202 +1,167 @@ -import React, { PureComponent } from 'react'; -import G2 from 'g2'; -import equal from '../equal'; - -const { Shape } = G2; - -const primaryColor = '#2F9CFF'; -const backgroundColor = '#F0F2F5'; - -/* eslint no-underscore-dangle: 0 */ -class Gauge extends PureComponent { - componentDidMount() { - setTimeout(() => { - this.renderChart(); - }, 10); +import React from 'react'; +import { Chart, Geom, Axis, Coord, Guide, Shape } from 'bizcharts'; +import autoHeight from '../autoHeight'; + +const { Arc, Html, Line } = Guide; + +const defaultFormatter = (val) => { + switch (val) { + case '2': + return '差'; + case '4': + return '中'; + case '6': + return '良'; + case '8': + return '优'; + default: + return ''; } - - componentWillReceiveProps(nextProps) { - if (!equal(this.props, nextProps)) { - setTimeout(() => { - this.renderChart(nextProps); - }, 10); - } - } - - componentWillUnmount() { - if (this.chart) { - this.chart.destroy(); - } - } - - handleRef = (n) => { - this.node = n; - } - - initChart(nextProps) { - const { title, color = primaryColor } = nextProps || this.props; - - Shape.registShape('point', 'dashBoard', { - drawShape(cfg, group) { - const originPoint = cfg.points[0]; - const point = this.parsePoint({ x: originPoint.x, y: 0.4 }); - - const center = this.parsePoint({ - x: 0, - y: 0, - }); - - const shape = group.addShape('polygon', { - attrs: { - points: [ - [center.x, center.y], - [point.x + 8, point.y], - [point.x + 8, point.y - 2], - [center.x, center.y - 2], - ], - radius: 2, - lineWidth: 2, - arrow: false, - fill: color, - }, - }); - - group.addShape('Marker', { - attrs: { - symbol: 'circle', - lineWidth: 2, - fill: color, - radius: 8, - x: center.x, - y: center.y, - }, - }); - group.addShape('Marker', { - attrs: { - symbol: 'circle', - lineWidth: 2, - fill: '#fff', - radius: 5, - x: center.x, - y: center.y, - }, - }); - - const { origin } = cfg; - group.addShape('text', { - attrs: { - x: center.x, - y: center.y + 80, - text: `${origin._origin.value}%`, - textAlign: 'center', - fontSize: 24, - fill: 'rgba(0, 0, 0, 0.85)', - }, - }); - group.addShape('text', { - attrs: { - x: center.x, - y: center.y + 45, - text: title, - textAlign: 'center', - fontSize: 14, - fill: 'rgba(0, 0, 0, 0.43)', - }, - }); - - return shape; - }, +}; + +Shape.registerShape('point', 'pointer', { + drawShape(cfg, group) { + let point = cfg.points[0]; + point = this.parsePoint(point); + const center = this.parsePoint({ + x: 0, + y: 0, }); - } - - renderChart(nextProps) { - const { - height, color = primaryColor, bgColor = backgroundColor, title, percent, format, - } = nextProps || this.props; - const data = [{ name: title, value: percent }]; - - if (this.chart) { - this.chart.clear(); - } - if (this.node) { - this.node.innerHTML = ''; - } - - this.initChart(nextProps); - - const chart = new G2.Chart({ - container: this.node, - forceFit: true, - height, - animate: false, - plotCfg: { - margin: [10, 10, 30, 10], + group.addShape('line', { + attrs: { + x1: center.x, + y1: center.y, + x2: point.x, + y2: point.y, + stroke: cfg.color, + lineWidth: 2, + lineCap: 'round', }, }); - - chart.source(data); - - chart.tooltip(false); - - chart.coord('gauge', { - startAngle: -1.2 * Math.PI, - endAngle: 0.20 * Math.PI, - }); - chart.col('value', { - type: 'linear', - nice: true, - min: 0, - max: 100, - tickCount: 6, - }); - chart.axis('value', { - subTick: false, - tickLine: { - stroke: color, - lineWidth: 2, - value: -14, + return group.addShape('circle', { + attrs: { + x: center.x, + y: center.y, + r: 6, + stroke: cfg.color, + lineWidth: 3, + fill: '#fff', }, - labelOffset: -12, - formatter: format, }); - chart.point().position('value').shape('dashBoard'); - draw(data); - - /* eslint no-shadow: 0 */ - function draw(data) { - const val = data[0].value; - const lineWidth = 12; - chart.guide().clear(); - - chart.guide().arc(() => { - return [0, 0.95]; - }, () => { - return [val, 0.95]; - }, { - stroke: color, - lineWidth, - }); - - chart.guide().arc(() => { - return [val, 0.95]; - }, (arg) => { - return [arg.max, 0.95]; - }, { - stroke: bgColor, - lineWidth, - }); - - chart.changeData(data); - } - - this.chart = chart; - } + }, +}); +@autoHeight() +export default class Gauge extends React.Component { render() { + const { + title, + height, + percent, + forceFit = true, + formatter = defaultFormatter, + color = '#2F9CFF', + bgColor = '#F0F2F5', + } = this.props; + const cols = { + value: { + type: 'linear', + min: 0, + max: 10, + tickCount: 6, + nice: true, + }, + }; + const data = [{ value: percent / 10 }]; return ( -
+ + + + + + + + + + + { + return ` +
+

${title}

+

+ ${data[0].value * 10}% +

+
`; + }} + /> +
+ +
); } } - -export default Gauge; diff --git a/src/components/Charts/MiniArea/index.js b/src/components/Charts/MiniArea/index.js index 65f09697..e84a3bc3 100644 --- a/src/components/Charts/MiniArea/index.js +++ b/src/components/Charts/MiniArea/index.js @@ -1,125 +1,91 @@ -import React, { PureComponent } from 'react'; -import G2 from 'g2'; -import equal from '../equal'; +import React from 'react'; +import { Chart, Axis, Tooltip, Geom } from 'bizcharts'; +import autoHeight from '../autoHeight'; import styles from '../index.less'; -class MiniArea extends PureComponent { - static defaultProps = { - borderColor: '#1890FF', - color: 'rgba(24, 144, 255, 0.2)', - }; - - componentDidMount() { - this.renderChart(this.props.data); - } - - componentWillReceiveProps(nextProps) { - if (!equal(this.props, nextProps)) { - this.renderChart(nextProps.data); - } - } - - componentWillUnmount() { - if (this.chart) { - this.chart.destroy(); - } - } - - handleRef = (n) => { - this.node = n; - } - - renderChart(data) { +@autoHeight() +export default class MiniArea extends React.Component { + render() { const { - height = 0, fit = true, color, borderWidth = 2, line, xAxis, yAxis, animate = true, + height, + data = [], + forceFit = true, + color = 'rgba(24, 144, 255, 0.2)', + scale = {}, + borderWidth = 2, + line, + xAxis, + yAxis, + animate = true, } = this.props; - const borderColor = this.props.borderColor || color; - - if (!data || (data && data.length < 1)) { - return; - } - - // clean - this.node.innerHTML = ''; - const chart = new G2.Chart({ - container: this.node, - forceFit: fit, - height: height + 54, - animate, - plotCfg: { - margin: [36, 5, 30, 5], - }, - legend: null, - }); - - if (!xAxis && !yAxis) { - chart.axis(false); - } - - if (xAxis) { - chart.axis('x', xAxis); - } else { - chart.axis('x', false); - } + const borderColor = this.props.borderColor || color; - if (yAxis) { - chart.axis('y', yAxis); - } else { - chart.axis('y', false); - } + const padding = [36, 5, 30, 5]; - const dataConfig = { + const scaleProps = { x: { type: 'cat', range: [0, 1], - ...xAxis, + ...scale.x, }, y: { min: 0, - ...yAxis, + ...scale.y, }, }; - chart.tooltip({ - title: null, - crosshairs: false, - map: { - title: null, - name: 'x', - value: 'y', - }, - }); - - const view = chart.createView(); - view.source(data, dataConfig); + const tooltip = [ + 'x*y', + (x, y) => ({ + name: x, + value: y, + }), + ]; - view.area().position('x*y').color(color).shape('smooth') - .style({ fillOpacity: 1 }); - - if (line) { - const view2 = chart.createView(); - view2.source(data, dataConfig); - view2.line().position('x*y').color(borderColor).size(borderWidth) - .shape('smooth'); - view2.tooltip(false); - } - chart.render(); - - this.chart = chart; - } - - render() { - const { height } = this.props; + const chartHeight = height + 54; return (
-
+ {height > 0 && ( + + + + + + {line ? ( + + ) : ( + + )} + + )}
); } } - -export default MiniArea; diff --git a/src/components/Charts/MiniBar/index.js b/src/components/Charts/MiniBar/index.js index 991571b7..92ee6b51 100644 --- a/src/components/Charts/MiniBar/index.js +++ b/src/components/Charts/MiniBar/index.js @@ -1,87 +1,50 @@ -import React, { PureComponent } from 'react'; -import G2 from 'g2'; -import equal from '../equal'; +import React from 'react'; +import { Chart, Tooltip, Geom } from 'bizcharts'; +import autoHeight from '../autoHeight'; import styles from '../index.less'; -class MiniBar extends PureComponent { - componentDidMount() { - this.renderChart(this.props.data); - } - - componentWillReceiveProps(nextProps) { - if (!equal(this.props, nextProps)) { - this.renderChart(nextProps.data); - } - } - - componentWillUnmount() { - if (this.chart) { - this.chart.destroy(); - } - } - - handleRef = (n) => { - this.node = n; - } - - renderChart(data) { - const { height = 0, fit = true, color = '#1890FF' } = this.props; - - if (!data || (data && data.length < 1)) { - return; - } - - // clean - this.node.innerHTML = ''; - - const { Frame } = G2; - const frame = new Frame(data); - - const chart = new G2.Chart({ - container: this.node, - forceFit: fit, - height: height + 54, - plotCfg: { - margin: [36, 5, 30, 5], - }, - legend: null, - }); - - chart.axis(false); +@autoHeight() +export default class MiniBar extends React.Component { + render() { + const { height, forceFit = true, color = '#1890FF', data = [] } = this.props; - chart.source(frame, { + const scale = { x: { type: 'cat', }, y: { min: 0, }, - }); + }; - chart.tooltip({ - title: null, - crosshairs: false, - map: { - name: 'x', - }, - }); - chart.interval().position('x*y').color(color); - chart.render(); + const padding = [36, 5, 30, 5]; - this.chart = chart; - } + const tooltip = [ + 'x*y', + (x, y) => ({ + name: x, + value: y, + }), + ]; - render() { - const { height } = this.props; + // for tooltip not to be hide + const chartHeight = height + 54; return (
-
+ + + +
); } } - -export default MiniBar; diff --git a/src/components/Charts/Pie/index.d.ts b/src/components/Charts/Pie/index.d.ts index 44a465d0..c029e79c 100644 --- a/src/components/Charts/Pie/index.d.ts +++ b/src/components/Charts/Pie/index.d.ts @@ -4,7 +4,7 @@ export interface PieProps { color?: string; height: number; hasLegend?: boolean; - margin?: [number, number, number, number]; + padding?: [number, number, number, number]; percent?: number; data?: Array<{ x: string; diff --git a/src/components/Charts/Pie/index.js b/src/components/Charts/Pie/index.js index 74cd2296..23be5f4b 100644 --- a/src/components/Charts/Pie/index.js +++ b/src/components/Charts/Pie/index.js @@ -1,40 +1,64 @@ import React, { Component } from 'react'; -import G2 from 'g2'; +import { Chart, Tooltip, Geom, Coord } from 'bizcharts'; +import { DataView } from '@antv/data-set'; import { Divider } from 'antd'; import classNames from 'classnames'; import ReactFitText from 'react-fittext'; import Debounce from 'lodash-decorators/debounce'; import Bind from 'lodash-decorators/bind'; -import equal from '../equal'; +import autoHeight from '../autoHeight'; + import styles from './index.less'; /* eslint react/no-danger:0 */ -class Pie extends Component { +@autoHeight() +export default class Pie extends Component { state = { legendData: [], - legendBlock: true, + legendBlock: false, }; componentDidMount() { - this.renderChart(); + this.getLengendData(); this.resize(); window.addEventListener('resize', this.resize); } componentWillReceiveProps(nextProps) { - if (!equal(this.props, nextProps)) { - this.renderChart(nextProps.data); + if (this.props.data !== nextProps.data) { + this.getLengendData(); } } componentWillUnmount() { window.removeEventListener('resize', this.resize); - if (this.chart) { - this.chart.destroy(); - } this.resize.cancel(); } + getG2Instance = (chart) => { + this.chart = chart; + }; + + // for custom lengend view + getLengendData = () => { + if (!this.chart) return; + const geom = this.chart.getAllGeoms()[0]; // 获取所有的图形 + const items = geom.get('dataArray') || []; // 获取图形对应的 + + const legendData = items.map((item) => { + /* eslint no-underscore-dangle:0 */ + const origin = item[0]._origin; + origin.color = item[0].color; + origin.checked = true; + return origin; + }); + + this.setState({ + legendData, + }); + }; + + // for window resize auto responsive legend @Bind() @Debounce(300) resize() { @@ -47,26 +71,18 @@ class Pie extends Component { if (!this.state.legendBlock) { this.setState({ legendBlock: true, - }, () => { - this.renderChart(); }); } } else if (this.state.legendBlock) { this.setState({ legendBlock: false, - }, () => { - this.renderChart(); }); } } - handleRef = (n) => { - this.node = n; - } - handleRoot = (n) => { this.root = n; - } + }; handleLegendClick = (item, i) => { const newItem = item; @@ -75,37 +91,57 @@ class Pie extends Component { const { legendData } = this.state; legendData[i] = newItem; + const filteredLegendData = legendData.filter(l => l.checked).map(l => l.x); + if (this.chart) { - const filterItem = legendData.filter(l => l.checked).map(l => l.x); - this.chart.filter('x', filterItem); - this.chart.repaint(); + this.chart.filter('x', val => filteredLegendData.indexOf(val) > -1); } this.setState({ legendData, }); - } - - renderChart(d) { - let data = d || this.props.data; + }; + render() { const { - height = 0, - hasLegend, - fit = true, - margin = [12, 0, 12, 0], percent, color, + valueFormat, + subTitle, + total, + hasLegend = false, + className, + style, + height, + forceFit = true, + percent = 0, + color, inner = 0.75, animate = true, colors, - lineWidth = 0, + lineWidth = 1, } = this.props; - const defaultColors = colors; + const { legendData, legendBlock } = this.state; + const pieClassName = classNames(styles.pie, className, { + [styles.hasLegend]: !!hasLegend, + [styles.legendBlock]: legendBlock, + }); + const defaultColors = colors; + let data = this.props.data || []; let selected = this.props.selected || true; - let tooltip = this.props.tooltips || true; - + let tooltip = this.props.tooltip || true; let formatColor; + + const scale = { + x: { + type: 'cat', + range: [0, 1], + }, + y: { + min: 0, + }, + }; + if (percent) { selected = false; tooltip = false; @@ -117,7 +153,6 @@ class Pie extends Component { } }; - /* eslint no-param-reassign: */ data = [ { x: '占比', @@ -130,131 +165,81 @@ class Pie extends Component { ]; } - if (!data || (data && data.length < 1)) { - return; - } - - // clean - this.node.innerHTML = ''; - - const { Stat } = G2; - - const chart = new G2.Chart({ - container: this.node, - forceFit: fit, - height, - plotCfg: { - margin, - }, - animate, - }); - - if (!tooltip) { - chart.tooltip(false); - } else { - chart.tooltip({ - title: null, - }); - } - - chart.axis(false); - chart.legend(false); - - chart.source(data, { - x: { - type: 'cat', - range: [0, 1], - }, - y: { - min: 0, - }, - }); - - chart.coord('theta', { - inner, - }); - - chart - .intervalStack() - .position(Stat.summary.percent('y')) - .style({ lineWidth, stroke: '#fff' }) - .color('x', percent ? formatColor : defaultColors) - .selected(selected); - - chart.render(); - - this.chart = chart; - - let legendData = []; - if (hasLegend) { - const geom = chart.getGeoms()[0]; // 获取所有的图形 - const items = geom.getData(); // 获取图形对应的数据 - legendData = items.map((item) => { - /* eslint no-underscore-dangle:0 */ - const origin = item._origin; - origin.color = item.color; - origin.checked = true; - return origin; - }); - } - - this.setState({ - legendData, - }); - } - - render() { - const { valueFormat, subTitle, total, hasLegend, className, style } = this.props; - const { legendData, legendBlock } = this.state; - const pieClassName = classNames(styles.pie, className, { - [styles.hasLegend]: !!hasLegend, - [styles.legendBlock]: legendBlock, + const tooltipFormat = [ + 'x*percent', + (x, p) => ({ + name: x, + value: `${(p * 100).toFixed(2)}%`, + }), + ]; + + const padding = [12, 0, 12, 0]; + + const dv = new DataView(); + dv.source(data).transform({ + type: 'percent', + field: 'y', + dimension: 'x', + as: 'percent', }); return (
-
- { - (subTitle || total) && ( -
- {subTitle &&

{subTitle}

} - { - // eslint-disable-next-line - total &&
- } -
- ) - } + + {!!tooltip && } + + + + + {(subTitle || total) && ( +
+ {subTitle &&

{subTitle}

} + {/* eslint-disable-next-line */} + {total &&
} +
+ )}
- { - hasLegend && ( -
    - { - legendData.map((item, i) => ( -
  • this.handleLegendClick(item, i)}> - - {item.x} - - {`${(item['..percent'] * 100).toFixed(2)}%`} - -
  • - )) - } -
- ) - } + {hasLegend && ( +
    + {legendData.map((item, i) => ( +
  • this.handleLegendClick(item, i)}> + + {item.x} + + {`${(item.percent * 100).toFixed(2)}%`} + +
  • + ))} +
+ )}
); } } - -export default Pie; diff --git a/src/components/Charts/Radar/index.d.ts b/src/components/Charts/Radar/index.d.ts index fa859785..b1707bf9 100644 --- a/src/components/Charts/Radar/index.d.ts +++ b/src/components/Charts/Radar/index.d.ts @@ -2,7 +2,7 @@ import * as React from "react"; export interface RadarProps { title?: React.ReactNode; height: number; - margin?: [number, number, number, number]; + padding?: [number, number, number, number]; hasLegend?: boolean; data: Array<{ name: string; diff --git a/src/components/Charts/Radar/index.js b/src/components/Charts/Radar/index.js index 8f338bc5..03aaa700 100644 --- a/src/components/Charts/Radar/index.js +++ b/src/components/Charts/Radar/index.js @@ -1,34 +1,57 @@ -import React, { PureComponent } from 'react'; -import G2 from 'g2'; +import React, { Component } from 'react'; +import { Chart, Tooltip, Geom, Coord, Axis } from 'bizcharts'; import { Row, Col } from 'antd'; -import equal from '../equal'; +import autoHeight from '../autoHeight'; import styles from './index.less'; /* eslint react/no-danger:0 */ -class Radar extends PureComponent { +@autoHeight() +export default class Radar extends Component { state = { legendData: [], - } + }; componentDidMount() { - this.renderChart(this.props.data); + this.getLengendData(); } componentWillReceiveProps(nextProps) { - if (!equal(this.props, nextProps)) { - this.renderChart(nextProps.data); + if (this.props.data !== nextProps.data) { + this.getLengendData(); } } - componentWillUnmount() { - if (this.chart) { - this.chart.destroy(); - } - } + getG2Instance = (chart) => { + this.chart = chart; + }; + + // for custom lengend view + getLengendData = () => { + if (!this.chart) return; + const geom = this.chart.getAllGeoms()[0]; // 获取所有的图形 + const items = geom.get('dataArray') || []; // 获取图形对应的 + + const legendData = items.map((item) => { + // eslint-disable-next-line + const origins = item.map(t => t._origin); + const result = { + name: origins[0].name, + color: item[0].color, + checked: true, + value: origins.reduce((p, n) => p + n.value, 0), + }; + + return result; + }); + + this.setState({ + legendData, + }); + }; handleRef = (n) => { this.node = n; - } + }; handleLegendClick = (item, i) => { const newItem = item; @@ -37,153 +60,121 @@ class Radar extends PureComponent { const { legendData } = this.state; legendData[i] = newItem; + const filteredLegendData = legendData.filter(l => l.checked).map(l => l.name); + if (this.chart) { - const filterItem = legendData.filter(l => l.checked).map(l => l.name); - this.chart.filter('name', filterItem); + this.chart.filter('name', val => filteredLegendData.indexOf(val) > -1); this.chart.repaint(); } this.setState({ legendData, }); - } - - renderChart(data) { - const { height = 0, - hasLegend = true, - fit = true, - tickCount = 4, - margin = [24, 30, 16, 30] } = this.props; + }; - const colors = [ - '#1890FF', '#FACC14', '#2FC25B', '#8543E0', '#F04864', '#13C2C2', '#fa8c16', '#a0d911', + render() { + const defaultColors = [ + '#1890FF', + '#FACC14', + '#2FC25B', + '#8543E0', + '#F04864', + '#13C2C2', + '#fa8c16', + '#a0d911', ]; - if (!data || (data && data.length < 1)) { - return; - } - - // clean - this.node.innerHTML = ''; - - const chart = new G2.Chart({ - container: this.node, - forceFit: fit, - height: height - (hasLegend ? 80 : 22), - plotCfg: { - margin, - }, - }); + const { + data = [], + height = 0, + title, + hasLegend = false, + forceFit = true, + tickCount = 4, + padding = [35, 30, 16, 30], + animate = true, + colors = defaultColors, + } = this.props; - this.chart = chart; + const { legendData } = this.state; - chart.source(data, { + const scale = { value: { min: 0, tickCount, }, - }); - - chart.coord('polar'); - chart.legend(false); - - chart.axis('label', { - line: null, - labelOffset: 8, - labels: { - label: { - fill: 'rgba(0, 0, 0, .65)', - }, - }, - grid: { - line: { - stroke: '#e9e9e9', - lineWidth: 1, - lineDash: [0, 0], - }, - }, - }); - - chart.axis('value', { - grid: { - type: 'polygon', - line: { - stroke: '#e9e9e9', - lineWidth: 1, - lineDash: [0, 0], - }, - }, - labels: { - label: { - fill: 'rgba(0, 0, 0, .65)', - }, - }, - }); - - chart.line().position('label*value').color('name', colors); - chart.point().position('label*value').color('name', colors).shape('circle') - .size(3); - - chart.render(); - - if (hasLegend) { - const geom = chart.getGeoms()[0]; // 获取所有的图形 - const items = geom.getData(); // 获取图形对应的数据 - const legendData = items.map((item) => { - /* eslint no-underscore-dangle:0 */ - const origin = item._origin; - const result = { - name: origin[0].name, - color: item.color, - checked: true, - value: origin.reduce((p, n) => p + n.value, 0), - }; - - return result; - }); - - this.setState({ - legendData, - }); - } - } + }; - render() { - const { height, title, hasLegend } = this.props; - const { legendData } = this.state; + const chartHeight = height - (hasLegend ? 80 : 22); return (
{title &&

{title}

} -
- { - hasLegend && ( - - { - legendData.map((item, i) => ( - this.handleLegendClick(item, i)} - > -
-

- - {item.name} -

-
{item.value}
-
- - )) - } -
- ) - } + + + + + + + + + {hasLegend && ( + + {legendData.map((item, i) => ( + this.handleLegendClick(item, i)} + > +
+

+ + {item.name} +

+
{item.value}
+
+ + ))} +
+ )}
); } } - -export default Radar; diff --git a/src/components/Charts/TagCloud/index.js b/src/components/Charts/TagCloud/index.js index d3f0d70c..6667c121 100644 --- a/src/components/Charts/TagCloud/index.js +++ b/src/components/Charts/TagCloud/index.js @@ -1,9 +1,10 @@ -import React, { PureComponent } from 'react'; -import classNames from 'classnames'; -import G2 from 'g2'; -import Cloud from 'g-cloud'; +import React, { Component } from 'react'; +import { Chart, Geom, Coord, Shape } from 'bizcharts'; +import DataSet from '@antv/data-set'; import Debounce from 'lodash-decorators/debounce'; import Bind from 'lodash-decorators/bind'; +import classNames from 'classnames'; +import autoHeight from '../autoHeight'; import styles from './index.less'; /* eslint no-underscore-dangle: 0 */ @@ -11,157 +12,130 @@ import styles from './index.less'; const imgUrl = 'https://gw.alipayobjects.com/zos/rmsportal/gWyeGLCdFFRavBGIDzWk.png'; -class TagCloud extends PureComponent { +@autoHeight() +class TagCloud extends Component { + state = { + dv: null, + }; + componentDidMount() { this.initTagCloud(); this.renderChart(); - window.addEventListener('resize', this.resize); } componentWillReceiveProps(nextProps) { - if (this.props.data !== nextProps.data) { - this.renderChart(nextProps.data); + if (JSON.stringify(nextProps.data) !== JSON.stringify(this.props.data)) { + this.renderChart(nextProps); } } componentWillUnmount() { window.removeEventListener('resize', this.resize); - this.renderChart.cancel(); } resize = () => { this.renderChart(); - } + }; - initTagCloud = () => { - const { Util, Shape } = G2; + saveRootRef = (node) => { + this.root = node; + }; + initTagCloud = () => { function getTextAttrs(cfg) { - const textAttrs = Util.mix(true, {}, { - fillOpacity: cfg.opacity, - fontSize: cfg.size, - rotate: cfg.origin._origin.rotate, - // rotate: cfg.origin._origin.rotate, - text: cfg.origin._origin.text, - textAlign: 'center', - fill: cfg.color, - textBaseline: 'Alphabetic', - }, cfg.style); - return textAttrs; + return Object.assign( + {}, + { + fillOpacity: cfg.opacity, + fontSize: cfg.origin._origin.size, + rotate: cfg.origin._origin.rotate, + text: cfg.origin._origin.text, + textAlign: 'center', + fontFamily: cfg.origin._origin.font, + fill: cfg.color, + textBaseline: 'Alphabetic', + }, + cfg.style + ); } // 给point注册一个词云的shape - Shape.registShape('point', 'cloud', { + Shape.registerShape('point', 'cloud', { drawShape(cfg, container) { - cfg.points = this.parsePoints(cfg.points); const attrs = getTextAttrs(cfg); - const shape = container.addShape('text', { - attrs: Util.mix(attrs, { - x: cfg.points[0].x, - y: cfg.points[0].y, + return container.addShape('text', { + attrs: Object.assign(attrs, { + x: cfg.x, + y: cfg.y, }), }); - return shape; }, }); - } - - saveRootRef = (node) => { - this.root = node; - } - - saveNodeRef = (node) => { - this.node = node; - } + }; @Bind() @Debounce(500) - renderChart(newData) { - const data = newData || this.props.data; - if (!data || data.length < 1) { - return; - } + renderChart = (nextProps) => { + // const colors = ['#1890FF', '#41D9C7', '#2FC25B', '#FACC14', '#9AE65C']; + const { data, height } = nextProps || this.props; - const colors = ['#1890FF', '#41D9C7', '#2FC25B', '#FACC14', '#9AE65C']; - - const height = this.props.height * 4; - let width = 0; - if (this.root) { - width = this.root.offsetWidth * 4; + if (data.length < 1 || !this.root) { + return; } - data.sort((a, b) => b.value - a.value); - - const max = data[0].value; - const min = data[data.length - 1].value; - - // 构造一个词云布局对象 - const layout = new Cloud({ - words: data, - width, - height, - - rotate: () => 0, - - // 设定文字大小配置函数(默认为12-24px的随机大小) - size: words => (((words.value - min) / (max - min)) * 50) + 30, - - // 设定文字内容 - text: words => words.name, - }); - - layout.image(imgUrl, (imageCloud) => { - // clean - if (this.node) { - this.node.innerHTML = ''; - } - - // 执行词云布局函数,并在回调函数中调用G2对结果进行绘制 - imageCloud.exec((texts) => { - const chart = new G2.Chart({ - container: this.node, - width, - height, - plotCfg: { - margin: 0, - }, - }); - - chart.legend(false); - chart.axis(false); - chart.tooltip(false); - - chart.source(texts); - - // 将词云坐标系调整为G2的坐标系 - chart.coord().reflect(); - - chart - .point() - .position('x*y') - .color('text', colors) - .size('size', size => size) - .shape('cloud') - .style({ - fontStyle: texts[0].style, - fontFamily: texts[0].font, - fontWeight: texts[0].weight, - }); + const h = height * 4; + const w = this.root.offsetWidth * 4; + + const imageMask = new Image(); + imageMask.crossOrigin = ''; + imageMask.src = imgUrl; + + imageMask.onload = () => { + const dv = new DataSet.View().source(data); + const range = dv.range('value'); + const [min, max] = range; + dv.transform({ + type: 'tag-cloud', + fields: ['name', 'value'], + imageMask, + font: 'Verdana', + size: [w, h], // 宽高设置最好根据 imageMask 做调整 + padding: 5, + timeInterval: 5000, // max execute time + rotate() { + return 0; + }, + fontSize(d) { + // eslint-disable-next-line + return Math.pow((d.value - min) / (max - min), 2) * (70 - 20) + 20; + }, + }); - chart.render(); + this.setState({ + dv, + w, + h, }); - }); - } + }; + }; render() { + const { className, height } = this.props; + const { dv, w, h } = this.state; + return (
-
+ {dv && ( + + + + + )}
); } diff --git a/src/components/Charts/TimelineChart/index.d.ts b/src/components/Charts/TimelineChart/index.d.ts index 5ea76a11..212b69e4 100644 --- a/src/components/Charts/TimelineChart/index.d.ts +++ b/src/components/Charts/TimelineChart/index.d.ts @@ -6,6 +6,7 @@ export interface TimelineChartProps { y2: string; }>; titleMap: { y1: string; y2: string }; + padding?: [number, number, number, number]; height?: number; } diff --git a/src/components/Charts/TimelineChart/index.js b/src/components/Charts/TimelineChart/index.js index 65048b85..38649837 100644 --- a/src/components/Charts/TimelineChart/index.js +++ b/src/components/Charts/TimelineChart/index.js @@ -1,125 +1,123 @@ -import React, { Component } from 'react'; -import G2 from 'g2'; -import Slider from 'g2-plugin-slider'; +import React from 'react'; +import { Chart, Tooltip, Geom, Legend, Axis } from 'bizcharts'; +import DataSet from '@antv/data-set'; +import Slider from 'bizcharts-plugin-slider'; +import autoHeight from '../autoHeight'; import styles from './index.less'; -class TimelineChart extends Component { - componentDidMount() { - this.renderChart(this.props.data); - } - - componentWillReceiveProps(nextProps) { - if (nextProps.data !== this.props.data) { - this.renderChart(nextProps.data); - } - } - - componentWillUnmount() { - if (this.chart) { - this.chart.destroy(); - } - if (this.slider) { - this.slider.destroy(); - } - } - - sliderId = `timeline-chart-slider-${Math.random() * 1000}` - - handleRef = (n) => { - this.node = n; - } - - renderChart(data) { - const { height = 400, margin = [60, 20, 40, 40], titleMap, borderWidth = 2 } = this.props; - - if (!data || (data && data.length < 1)) { - return; - } - - // clean - if (this.sliderId) { - document.getElementById(this.sliderId).innerHTML = ''; - } - this.node.innerHTML = ''; - - const chart = new G2.Chart({ - container: this.node, - forceFit: true, - height, - plotCfg: { - margin, +@autoHeight() +export default class TimelineChart extends React.Component { + render() { + const { + title, + height = 400, + padding = [60, 20, 40, 40], + titleMap = { + y1: 'y1', + y2: 'y2', }, - }); - - chart.axis('x', { - title: false, - }); - chart.axis('y1', { - title: false, - }); - chart.axis('y2', false); - - chart.legend({ - mode: false, - position: 'top', - }); + borderWidth = 2, + data = [ + { + x: 0, + y1: 0, + y2: 0, + }, + ], + } = this.props; + + data.sort((a, b) => a.x - b.x); let max; if (data[0] && data[0].y1 && data[0].y2) { - max = Math.max(data.sort((a, b) => b.y1 - a.y1)[0].y1, - data.sort((a, b) => b.y2 - a.y2)[0].y2); + max = Math.max( + [...data].sort((a, b) => b.y1 - a.y1)[0].y1, + [...data].sort((a, b) => b.y2 - a.y2)[0].y2 + ); } - chart.source(data, { - x: { - type: 'timeCat', - tickCount: 16, - mask: 'HH:MM', - range: [0, 1], - }, - y1: { - alias: titleMap.y1, - max, - min: 0, + const ds = new DataSet({ + state: { + start: data[0].x, + end: data[data.length - 1].x, }, - y2: { - alias: titleMap.y2, + }); + + const dv = ds.createView(); + dv + .source(data) + .transform({ + type: 'filter', + callback: (obj) => { + const date = obj.x; + return date <= ds.state.end && date >= ds.state.start; + }, + }) + .transform({ + type: 'map', + callback(row) { + const newRow = { ...row }; + newRow[titleMap.y1] = row.y1; + newRow[titleMap.y2] = row.y2; + return newRow; + }, + }) + .transform({ + type: 'fold', + fields: [titleMap.y1, titleMap.y2], // 展开字段集 + key: 'key', // key字段 + value: 'value', // value字段 + }); + + const timeScale = { + type: 'time', + tickCount: 10, + mask: 'HH:MM', + range: [0, 1], + }; + + const cols = { + x: timeScale, + value: { max, min: 0, }, - }); - - chart.line().position('x*y1').color('#1890FF').size(borderWidth); - chart.line().position('x*y2').color('#2FC25B').size(borderWidth); - - this.chart = chart; - - /* eslint new-cap:0 */ - const slider = new Slider({ - domId: this.sliderId, - height: 26, - xDim: 'x', - yDim: 'y1', - charts: [chart], - }); - slider.render(); - - this.slider = slider; - } - - render() { - const { height, title } = this.props; + }; + + const SliderGen = () => ( + { + ds.setState('start', startValue); + ds.setState('end', endValue); + }} + /> + ); return ( -
+
- { title &&

{title}

} -
-
+ {title &&

{title}

} + + + + + + +
+ +
); } } - -export default TimelineChart; diff --git a/src/components/Charts/WaterWave/index.js b/src/components/Charts/WaterWave/index.js index a9eece61..5b463ad5 100644 --- a/src/components/Charts/WaterWave/index.js +++ b/src/components/Charts/WaterWave/index.js @@ -1,16 +1,16 @@ import React, { PureComponent } from 'react'; +import autoHeight from '../autoHeight'; import styles from './index.less'; /* eslint no-return-assign: 0 */ +/* eslint no-mixed-operators: 0 */ // riddle: https://riddle.alibaba-inc.com/riddles/2d9a4b90 -class WaterWave extends PureComponent { - static defaultProps = { - height: 160, - } +@autoHeight() +export default class WaterWave extends PureComponent { state = { radio: 1, - } + }; componentDidMount() { this.renderChart(); @@ -33,7 +33,7 @@ class WaterWave extends PureComponent { this.setState({ radio: offsetWidth < height ? offsetWidth / height : 1, }); - } + }; renderChart() { const { percent, color = '#1890FF' } = this.props; @@ -51,12 +51,12 @@ class WaterWave extends PureComponent { const canvasHeight = canvas.height; const radius = canvasWidth / 2; const lineWidth = 2; - const cR = radius - (lineWidth); + const cR = radius - lineWidth; ctx.beginPath(); ctx.lineWidth = lineWidth * 2; - const axisLength = canvasWidth - (lineWidth); + const axisLength = canvasWidth - lineWidth; const unit = axisLength / 8; const range = 0.2; // 振幅 let currRange = range; @@ -66,15 +66,12 @@ class WaterWave extends PureComponent { const waveupsp = 0.005; // 水波上涨速度 let arcStack = []; - const bR = radius - (lineWidth); + const bR = radius - lineWidth; const circleOffset = -(Math.PI / 2); let circleLock = true; - for (let i = circleOffset; i < circleOffset + (2 * Math.PI); i += 1 / (8 * Math.PI)) { - arcStack.push([ - radius + (bR * Math.cos(i)), - radius + (bR * Math.sin(i)), - ]); + for (let i = circleOffset; i < circleOffset + 2 * Math.PI; i += 1 / (8 * Math.PI)) { + arcStack.push([radius + bR * Math.cos(i), radius + bR * Math.sin(i)]); } const cStartPoint = arcStack.shift(); @@ -87,10 +84,10 @@ class WaterWave extends PureComponent { const sinStack = []; for (let i = xOffset; i <= xOffset + axisLength; i += 20 / axisLength) { - const x = sp + ((xOffset + i) / unit); + const x = sp + (xOffset + i) / unit; const y = Math.sin(x) * currRange; const dx = i; - const dy = ((2 * cR * (1 - currData)) + (radius - cR)) - (unit * y); + const dy = 2 * cR * (1 - currData) + (radius - cR) - unit * y; ctx.lineTo(dx, dy); sinStack.push([dx, dy]); @@ -130,7 +127,7 @@ class WaterWave extends PureComponent { ctx.beginPath(); ctx.save(); - ctx.arc(radius, radius, radius - (3 * lineWidth), 0, 2 * Math.PI, 1); + ctx.arc(radius, radius, radius - 3 * lineWidth, 0, 2 * Math.PI, 1); ctx.restore(); ctx.clip(); @@ -157,10 +154,10 @@ class WaterWave extends PureComponent { currRange -= t; } } - if ((data - currData) > 0) { + if (data - currData > 0) { currData += waveupsp; } - if ((data - currData) < 0) { + if (data - currData < 0) { currData -= waveupsp; } @@ -177,7 +174,11 @@ class WaterWave extends PureComponent { const { radio } = this.state; const { percent, title, height } = this.props; return ( -
(this.root = n)} style={{ transform: `scale(${radio})` }}> +
(this.root = n)} + style={{ transform: `scale(${radio})` }} + >
- { - title && {title} - } + {title && {title}}

{percent}%

); } } - -export default WaterWave; diff --git a/src/components/Charts/autoHeight.js b/src/components/Charts/autoHeight.js new file mode 100644 index 00000000..d8582ffd --- /dev/null +++ b/src/components/Charts/autoHeight.js @@ -0,0 +1,63 @@ +/* eslint eqeqeq: 0 */ +import React from 'react'; + +function computeHeight(node) { + const totalHeight = parseInt(getComputedStyle(node).height, 10); + const padding = + parseInt(getComputedStyle(node).paddingTop, 10) + + parseInt(getComputedStyle(node).paddingBottom, 10); + return totalHeight - padding; +} + +function getAutoHeight(n) { + if (!n) { + return 0; + } + + let node = n; + + let height = computeHeight(node); + + while (!height) { + node = node.parentNode; + if (node) { + height = computeHeight(node); + } else { + break; + } + } + + return height; +} + +const autoHeight = () => (WrappedComponent) => { + return class extends React.Component { + state = { + computedHeight: 0, + }; + + componentDidMount() { + const { height } = this.props; + if (!height) { + const h = getAutoHeight(this.root); + // eslint-disable-next-line + this.setState({ computedHeight: h }); + } + } + + handleRoot = (node) => { + this.root = node; + }; + + render() { + const { height } = this.props; + const { computedHeight } = this.state; + const h = height || computedHeight; + return ( +
{h > 0 && }
+ ); + } + }; +}; + +export default autoHeight; diff --git a/src/components/Charts/equal.js b/src/components/Charts/equal.js deleted file mode 100644 index ff3a4c70..00000000 --- a/src/components/Charts/equal.js +++ /dev/null @@ -1,17 +0,0 @@ -/* eslint eqeqeq: 0 */ - -function equal(old, target) { - let r = true; - for (const prop in old) { - if (typeof old[prop] === 'function' && typeof target[prop] === 'function') { - if (old[prop].toString() != target[prop].toString()) { - r = false; - } - } else if (old[prop] != target[prop]) { - r = false; - } - } - return r; -} - -export default equal; diff --git a/src/g2.js b/src/g2.js index 0ff40f51..81ca055f 100644 --- a/src/g2.js +++ b/src/g2.js @@ -1,26 +1,4 @@ // 全局 G2 设置 -import G2 from 'g2'; +import { track } from 'bizcharts'; -G2.track(false); - -const colors = [ - '#8543E0', '#F04864', '#FACC14', '#1890FF', '#13C2C2', '#2FC25B', '#fa8c16', '#a0d911', -]; - -const config = { - ...G2.Theme, - defaultColor: '#1089ff', - colors: { - default: colors, - intervalStack: colors, - }, - tooltip: { - background: { - radius: 4, - fill: '#000', - fillOpacity: 0.75, - }, - }, -}; - -G2.Global.setTheme(config); +track(false); diff --git a/src/index.ejs b/src/index.ejs index 8db03eb1..586f62e8 100644 --- a/src/index.ejs +++ b/src/index.ejs @@ -1,5 +1,6 @@ + @@ -7,8 +8,9 @@ Ant Design Pro +
- - + + \ No newline at end of file diff --git a/src/index.less b/src/index.less index 047d86cc..b9277ead 100644 --- a/src/index.less +++ b/src/index.less @@ -1,7 +1,13 @@ -html, body, :global(#root) { +html, +body, +:global(#root) { height: 100%; } +canvas { + display: block; +} + body { text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; diff --git a/src/routes/Dashboard/Analysis.js b/src/routes/Dashboard/Analysis.js index 765c818b..8cfe32a3 100644 --- a/src/routes/Dashboard/Analysis.js +++ b/src/routes/Dashboard/Analysis.js @@ -1,9 +1,29 @@ import React, { Component } from 'react'; import { connect } from 'dva'; -import { Row, Col, Icon, Card, Tabs, Table, Radio, DatePicker, Tooltip, Menu, Dropdown } from 'antd'; +import { + Row, + Col, + Icon, + Card, + Tabs, + Table, + Radio, + DatePicker, + Tooltip, + Menu, + Dropdown, +} from 'antd'; import numeral from 'numeral'; import { - ChartCard, yuan, MiniArea, MiniBar, MiniProgress, Field, Bar, Pie, TimelineChart, + ChartCard, + yuan, + MiniArea, + MiniBar, + MiniProgress, + Field, + Bar, + Pie, + TimelineChart, } from '../../components/Charts'; import Trend from '../../components/Trend'; import NumberInfo from '../../components/NumberInfo'; @@ -30,7 +50,7 @@ export default class Analysis extends Component { salesType: 'all', currentTabKey: '', rangePickerValue: getTimeDistance('year'), - } + }; componentDidMount() { this.props.dispatch({ @@ -49,13 +69,13 @@ export default class Analysis extends Component { this.setState({ salesType: e.target.value, }); - } + }; handleTabChange = (key) => { this.setState({ currentTabKey: key, }); - } + }; handleRangePickerChange = (rangePickerValue) => { this.setState({ @@ -65,7 +85,7 @@ export default class Analysis extends Component { this.props.dispatch({ type: 'chart/fetchSalesData', }); - } + }; selectDate = (type) => { this.setState({ @@ -75,7 +95,7 @@ export default class Analysis extends Component { this.props.dispatch({ type: 'chart/fetchSalesData', }); - } + }; isActive(type) { const { rangePickerValue } = this.state; @@ -83,7 +103,10 @@ export default class Analysis extends Component { if (!rangePickerValue[0] || !rangePickerValue[1]) { return; } - if (rangePickerValue[0].isSame(value[0], 'day') && rangePickerValue[1].isSame(value[1], 'day')) { + if ( + rangePickerValue[0].isSame(value[0], 'day') && + rangePickerValue[1].isSame(value[1], 'day') + ) { return styles.currentDate; } } @@ -104,10 +127,10 @@ export default class Analysis extends Component { loading, } = chart; - const salesPieData = salesType === 'all' ? - salesTypeData - : - (salesType === 'online' ? salesTypeDataOnline : salesTypeDataOffline); + const salesPieData = + salesType === 'all' + ? salesTypeData + : salesType === 'online' ? salesTypeDataOnline : salesTypeDataOffline; const menu = ( @@ -191,13 +214,13 @@ export default class Analysis extends Component { subTitle="转化率" gap={2} total={`${data.cvr * 100}%`} - theme={(currentKey !== data.name) && 'light'} + theme={currentKey !== data.name && 'light'} /> } + action={ + + + + } total={yuan(126560)} footer={} contentHeight={46} @@ -241,38 +268,43 @@ export default class Analysis extends Component { } + action={ + + + + } total={numeral(8846).format('0,0')} footer={} contentHeight={46} > - + } + action={ + + + + } total={numeral(6560).format('0,0')} footer={} contentHeight={46} > - + } + action={ + + + + } total="78%" footer={
@@ -291,37 +323,27 @@ export default class Analysis extends Component { - +
- +

门店销售额排名

    - { - rankingListData.map((item, i) => ( -
  • - {i + 1} - {item.title} - {numeral(item.total).format('0,0')} -
  • - )) - } + {rankingListData.map((item, i) => ( +
  • + {i + 1} + {item.title} + {numeral(item.total).format('0,0')} +
  • + ))}
@@ -331,26 +353,20 @@ export default class Analysis extends Component {
- +

门店访问量排名

    - { - rankingListData.map((item, i) => ( -
  • - {i + 1} - {item.title} - {numeral(item.total).format('0,0')} -
  • - )) - } + {rankingListData.map((item, i) => ( +
  • + {i + 1} + {item.title} + {numeral(item.total).format('0,0')} +
  • + ))}
@@ -385,11 +401,7 @@ export default class Analysis extends Component { status="up" subTotal={17.1} /> - + - +
{iconGroup}
@@ -436,7 +444,7 @@ export default class Analysis extends Component {
- )} + } style={{ marginTop: 24, minHeight: 509 }} >

销售额

@@ -460,25 +468,18 @@ export default class Analysis extends Component { bodyStyle={{ padding: '0 0 32px 0' }} style={{ marginTop: 32 }} > - - { - offlineData.map(shop => ( - } - key={shop.name} - > -
- -
-
) - ) - } + + {offlineData.map(shop => ( + } key={shop.name}> +
+ +
+
+ ))}
diff --git a/src/routes/Dashboard/Monitor.js b/src/routes/Dashboard/Monitor.js index 5c888a65..3bc560d7 100644 --- a/src/routes/Dashboard/Monitor.js +++ b/src/routes/Dashboard/Monitor.js @@ -40,16 +40,10 @@ export default class Monitor extends PureComponent { />
- + - } - /> + } />
- map + map
@@ -143,20 +140,17 @@ export default class Monitor extends PureComponent {
- - + + - - + + -- GitLab