From a2df1bad33874fc6d9f96b0ceb1a6ce97b2e7e80 Mon Sep 17 00:00:00 2001 From: king <18310653075@163.com> Date: 星期二, 26 五月 2020 19:35:40 +0800 Subject: [PATCH] 2020-05-26 --- src/tabviews/zshare/chartcomponent/index.jsx | 580 ++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 files changed, 484 insertions(+), 96 deletions(-) diff --git a/src/tabviews/zshare/chartcomponent/index.jsx b/src/tabviews/zshare/chartcomponent/index.jsx index f936550..672d8e0 100644 --- a/src/tabviews/zshare/chartcomponent/index.jsx +++ b/src/tabviews/zshare/chartcomponent/index.jsx @@ -3,7 +3,7 @@ import { is, fromJS } from 'immutable' import { Chart } from '@antv/g2' import DataSet from '@antv/data-set' -import { Spin, Empty } from 'antd' +import { Spin, Empty, Select } from 'antd' import Utils from '@/utils/utils.js' import zhCN from '@/locales/zh-CN/model.js' @@ -21,16 +21,44 @@ state = { dict: (!localStorage.getItem('lang') || localStorage.getItem('lang') === 'zh-CN') ? zhCN : enUS, empty: true, - chartId: Utils.getuuid() + chartId: Utils.getuuid(), + chartData: [], + chartFields: [], + selectFields: [] } componentDidMount () { - this.viewrender() + const { plot, data } = this.props + + let _state = {} + + if (plot.datatype === 'statistics' && (plot.chartType === 'line' || plot.chartType === 'bar')) { + let result = this.getStaticMsg(data) + _state.chartData = result.data + _state.chartFields = result.chartFields + _state.selectFields = result.selectFields + + this.setState(_state, () => { + this.viewrender() + }) + } else { + this.viewrender() + } } UNSAFE_componentWillReceiveProps (nextProps) { + const { plot } = this.props if (!is(fromJS(this.props.data), fromJS(nextProps.data))) { - this.setState({}, () => { + let _state = {} + + if (plot.datatype === 'statistics' && (plot.chartType === 'line' || plot.chartType === 'bar')) { + let result = this.getStaticMsg(nextProps.data) + _state.chartData = result.data + _state.chartFields = result.chartFields + _state.selectFields = result.selectFields + } + + this.setState(_state, () => { let _element = document.getElementById(this.state.chartId) if (_element) { _element.innerHTML = '' @@ -82,6 +110,7 @@ vFields.forEach(field => { _item[field] += item[field] }) + _mdata.set(item[plot.Xaxis], _item) } }) @@ -116,6 +145,7 @@ vFields.forEach(field => { _item[field] += item[field] }) + _mdata.set(item[plot.Xaxis], _item) } }) @@ -151,6 +181,170 @@ _data = [..._mdata.values()] } + if (plot.correction && plot.chartType === 'bar' && plot.enabled !== 'true' && _data.length > 0 && _data.length < plot.correction) { + if (plot.customs && plot.customs.filter(cell => cell.chartType !== 'bar').length === 0) { + let _num = plot.correction - _data.length + for (let i = 0; i < _num; i++) { + let _val = Array( i + 2 ).join(' ') + let _cell = {} + _cell[plot.Xaxis] = _val + _columns.forEach(col => { + _cell[col.field] = '' + }) + + _data.push(_cell) + } + } + } + + this.setState({empty: _data.length === 0}) + return _data + } + + getStaticMsg = (data) => { + const { plot, config } = this.props + + let _column = config.columns.filter(col => plot.InfoValue === col.field)[0] + let percent = false + let decimal = 0 + if (_column && _column.format === 'percent') { + percent = true + } + if (_column) { + decimal = _column.decimal + } + + if (!data) { + this.setState({empty: true}) + return {data: [], chartFields: [], selectFields: []} + } + + let _data = [] + let _cdata = fromJS(data).toJS() + let _chartFields = [] + let _selectFields = [] + + if (plot.repeat === 'average') { + let _mdata = new Map() + _cdata.forEach(item => { + if (!item[plot.InfoType] || !item[plot.Xaxis]) return + _chartFields.push(item[plot.InfoType]) + + item.$uuid = item[plot.InfoType] + item[plot.Xaxis] + if (typeof(item[plot.InfoValue]) !== 'number') { + item[plot.InfoValue] = parseFloat(plot.InfoValue) + if (isNaN(item[plot.InfoValue])) { + item[plot.InfoValue] = 0 + } + } + if (percent) { + item[plot.InfoValue] = item[plot.InfoValue] * 100 + } + + if (!_mdata.has(item.$uuid)) { + item.$count = 1 + _mdata.set(item.$uuid, item) + } else { + let _item = _mdata.get(item.$uuid) + _item.$count++ + _item[plot.InfoValue] += item[plot.InfoValue] + _mdata.set(item.$uuid, _item) + } + }) + + _data = [..._mdata.values()] + _data = _data.map(item => { + item[plot.InfoValue] = item[plot.InfoValue] / item.$count + item[plot.InfoValue] = item[plot.InfoValue].toFixed(decimal) + item[plot.InfoValue] = +item[plot.InfoValue] + + return item + }) + } else if (plot.repeat === 'cumsum') { + let _mdata = new Map() + _cdata.forEach(item => { + if (!item[plot.InfoType] || !item[plot.Xaxis]) return + _chartFields.push(item[plot.InfoType]) + + item.$uuid = item[plot.InfoType] + item[plot.Xaxis] + + if (typeof(item[plot.InfoValue]) !== 'number') { + item[plot.InfoValue] = parseFloat(plot.InfoValue) + if (isNaN(item[plot.InfoValue])) { + item[plot.InfoValue] = 0 + } + } + if (percent) { + item[plot.InfoValue] = item[plot.InfoValue] * 100 + } + + if (!_mdata.has(item.$uuid)) { + _mdata.set(item.$uuid, item) + } else { + let _item = _mdata.get(item.$uuid) + _item[plot.InfoValue] += item[plot.InfoValue] + _mdata.set(item.$uuid, _item) + } + }) + + _data = [..._mdata.values()] + _data = _data.map(item => { + item[plot.InfoValue] = item[plot.InfoValue].toFixed(decimal) + item[plot.InfoValue] = +item[plot.InfoValue] + + return item + }) + } else { // plot.repeat === 'unrepeat' + let _mdata = new Map() + _cdata.forEach(item => { + if (!item[plot.InfoType] || !item[plot.Xaxis]) return + _chartFields.push(item[plot.InfoType]) + + item.$uuid = item[plot.InfoType] + item[plot.Xaxis] + + if (!_mdata.has(item.$uuid)) { + if (typeof(item[plot.InfoValue]) !== 'number') { + item[plot.InfoValue] = parseFloat(plot.InfoValue) + if (isNaN(item[plot.InfoValue])) { + item[plot.InfoValue] = 0 + } + } + if (percent) { + item[plot.InfoValue] = item[plot.InfoValue] * 100 + } + + item[plot.InfoValue] = item[plot.InfoValue].toFixed(decimal) + item[plot.InfoValue] = +item[plot.InfoValue] + + _mdata.set(item.$uuid, item) + } + }) + + _data = [..._mdata.values()] + } + + _chartFields = Array.from(new Set(_chartFields)) + + if (plot.InfoDefNumber >= _chartFields.length) { + _selectFields = _chartFields + } else { + _selectFields = _chartFields.slice(0, plot.InfoDefNumber) + } + + return {data: _data, chartFields: _chartFields, selectFields: _selectFields} + } + + getStaticData = () => { + const { plot } = this.props + const { chartData, chartFields, selectFields } = this.state + + let _data = [] + if (selectFields.length === chartFields.length) { + _data = chartData + } else { + _data = chartData.filter(item => selectFields.includes(item[plot.InfoType])) + } + this.setState({empty: _data.length === 0}) return _data } @@ -170,37 +364,52 @@ linerender = () => { const { plot, config } = this.props - let transfield = {} - config.columns.forEach(col => { - if (col.field) { - transfield[col.field] = col.label - } - }) - // const colors = ['#f49d37', '#f03838', '#35d1d1', '#5be56b', '#4e7af0', '#ebcc21'] - let X_axis = plot.Xaxis - let Y_axis = plot.Yaxis + let _data = [] + let _valfield = 'value' + let _typefield = 'key' - let data = this.getdata() + if (plot.datatype === 'statistics') { + _valfield = plot.InfoValue + _typefield = plot.InfoType - const ds = new DataSet() - const dv = ds.createView().source(data) - - dv.transform({ - type: 'fold', - fields: [...Y_axis], - key: 'key', // key瀛楁 - value: 'value', // value瀛楁 - // retains: [], // 淇濈暀瀛楁闆嗭紝榛樿涓洪櫎 fields 浠ュ鐨勬墍鏈夊瓧娈� - }) - - if (plot.Xaxis) { - dv.transform({ - type: 'map', - callback(row) { - row.key = transfield[row.key] - return row - }, + _data = this.getStaticData() + } else { + let transfield = {} + config.columns.forEach(col => { + if (col.field) { + transfield[col.field] = col.label + } }) + + let data = this.getdata() + + if (plot.enabled === 'true') { + this.customrender(data, transfield) + return + } + + const ds = new DataSet() + const dv = ds.createView().source(data) + + dv.transform({ + type: 'fold', + fields: [...plot.Yaxis], + key: 'key', // key瀛楁 + value: _valfield, // value瀛楁 + // retains: [], // 淇濈暀瀛楁闆嗭紝榛樿涓洪櫎 fields 浠ュ鐨勬墍鏈夊瓧娈� + }) + + if (plot.Xaxis) { + dv.transform({ + type: 'map', + callback(row) { + row.key = transfield[row.key] + return row + }, + }) + } + + _data = dv.rows } const chart = new Chart({ @@ -209,14 +418,14 @@ height: plot.height || 400 }) - chart.data(dv.rows) + chart.data(_data) if (plot.coordinate !== 'polar') { - chart.scale(X_axis, { + chart.scale(plot.Xaxis, { range: [0, 1] }) } - chart.scale('value', { + chart.scale(_valfield, { nice: true }) @@ -249,19 +458,19 @@ let _chart = chart .line() - .position(`${X_axis}*value`) - .color('key') + .position(`${plot.Xaxis}*${_valfield}`) + .color(_typefield) .shape(plot.shape || 'smooth') if (plot.label === 'true') { - _chart.label('value') + _chart.label(_valfield) } if (plot.point === 'true') { chart .point() - .position(`${X_axis}*value`) - .color('key') + .position(`${plot.Xaxis}*${_valfield}`) + .color(_typefield) .size(3) .shape('circle') } @@ -269,62 +478,76 @@ chart.render() } - barrender = () => { - const { plot, config } = this.props + customrender = (data, transfield) => { + const { plot } = this.props - let transfield = {} - config.columns.forEach(col => { - if (col.field) { - transfield[col.field] = col.label + let barfields = [] + let fields = [] + let legends = [] + + plot.customs.forEach(item => { + item.name = transfield[item.field] || item.field + if (item.axis === 'left') { + item.index = 0 + } else if (item.axis === 'right') { + item.index = 1 + } else { + item.index = 2 } - }) - let X_axis = plot.Xaxis - let Y_axis = plot.Yaxis - let data = this.getdata() + if (item.chartType === 'bar') { + barfields.push(item.field) + fields.unshift(item) + } else { + fields.push(item) + } + + legends.push({ + value: item.name, + name: item.name, + marker: { symbol: item.chartType === 'bar' ? 'square' : 'hyphen', style: { stroke: item.color,fill: item.color, r: 5, lineWidth: 2 } } + }) + }) + + fields.sort((a, b) => a.index - b.index) const ds = new DataSet() const dv = ds.createView().source(data) - dv.transform({ - type: 'fold', - fields: [...Y_axis], - key: 'key', - value: 'value' + type: 'map', + callback(row) { + fields.forEach(line => { + row[line.name] = row[line.field] + }) + return row + } }) - if (plot.Xaxis) { - dv.transform({ - type: 'map', - callback(row) { - row.key = transfield[row.key] - return row - }, - }) - } - const chart = new Chart({ container: this.state.chartId, autoFit: true, height: plot.height || 400 }) - // dodge is not support linear attribute, please use category attribute! 鏃堕棿鏍煎紡 - if (dv.rows[0] && dv.rows[0][X_axis] && /^\d{4}-\d{2}-\d{2}(\s\d{2}:\d{2}:\d{2})?/.test(dv.rows[0][X_axis])) { - dv.rows[0][X_axis] += ' ' - } - chart.data(dv.rows) - chart.scale('value', { - nice: true - }) + if (plot.coordinate !== 'polar' && barfields.length === 0) { + chart.scale(plot.Xaxis, { + range: [0, 1] + }) + } else { + chart.scale(plot.Xaxis, { + range: [0.05, 0.95] + }) + } if (!plot.legend || plot.legend === 'hidden') { chart.legend(false) } else { chart.legend({ - position: plot.legend + custom: true, + position: plot.legend, + items: legends, }) } @@ -347,11 +570,162 @@ }) } + fields.forEach((item, i) => { + if (i === 0) { + chart.axis(item.name, { + grid: {}, + title: {}, + label: {} + }) + } else if (i === 1 && item.axis !== 'unset') { + chart.axis(item.name, { + grid: null, + title: {}, + label: {} + }) + } else { + chart.axis(item.name, { + grid: null, + title: null, + label: null + }) + } + + if (item.chartType === 'bar') { + let _chart = chart + .interval() + .position(`${plot.Xaxis}*${item.name}`) + .color(item.color) + .shape(item.shape) + + if (item.label === 'true') { + _chart.label(item.name) + } + } else if (item.chartType === 'line') { + let _chart = chart + .line() + .position(`${plot.Xaxis}*${item.name}`) + .color(item.color) + .shape(item.shape) + + if (item.label === 'true') { + _chart.label(item.name) + } + + if (plot.point === 'true') { + chart + .point() + .position(`${plot.Xaxis}*${item.name}`) + .color(item.color) + .size(3) + .shape('circle') + } + } + }) + + chart.render() + } + + barrender = () => { + const { plot, config } = this.props + + let _data = [] + let _valfield = 'value' + let _typefield = 'key' + + if (plot.datatype === 'statistics') { + _valfield = plot.InfoValue + _typefield = plot.InfoType + + _data = this.getStaticData() + } else { + let transfield = {} + config.columns.forEach(col => { + if (col.field) { + transfield[col.field] = col.label + } + }) + + let data = this.getdata() + + if (plot.enabled === 'true') { + this.customrender(data, transfield) + return + } + + const ds = new DataSet() + const dv = ds.createView().source(data) + + dv.transform({ + type: 'fold', + fields: [...plot.Yaxis], + key: 'key', + value: _valfield + }) + + if (plot.Xaxis) { + dv.transform({ + type: 'map', + callback(row) { + row.key = transfield[row.key] + return row + }, + }) + } + + _data = dv.rows + } + + const chart = new Chart({ + container: this.state.chartId, + autoFit: true, + height: plot.height || 400 + }) + + // dodge is not support linear attribute, please use category attribute! 鏃堕棿鏍煎紡 + if (_data[0] && _data[0][plot.Xaxis] && /^\d{4}-\d{2}-\d{2}(\s\d{2}:\d{2}:\d{2})?/.test(_data[0][plot.Xaxis])) { + _data[0][plot.Xaxis] += ' ' + } + + chart.data(_data) + + chart.scale(_valfield, { + nice: true + }) + + if (!plot.legend || plot.legend === 'hidden') { + chart.legend(false) + } else { + chart.legend({ + position: plot.legend + }) + } + + if (plot.tooltip !== 'true') { + chart.tooltip(false) + } else { + chart.tooltip({ + showMarkers: false, + shared: true + }) + } + + if (plot.transpose === 'true') { + chart.coordinate().transpose() + } + + if (plot.coordinate === 'polar') { + chart.coordinate('polar', { + innerRadius: 0.1, + radius: 0.8 + }) + } + if (plot.adjust !== 'stack') { chart .interval() - .position(`${X_axis}*value`) - .color('key') + .position(`${plot.Xaxis}*${_valfield}`) + .color(_typefield) .adjust([ { type: 'dodge', @@ -362,8 +736,8 @@ } else if (plot.adjust === 'stack') { chart .interval() - .position(`${X_axis}*value`) - .color('key') + .position(`${plot.Xaxis}*${_valfield}`) + .color(_typefield) .adjust('stack') .shape(plot.shape || 'rect') } @@ -380,8 +754,6 @@ transfield[col.field] = col.label } }) - let X_axis = plot.Xaxis - let Y_axis = plot.Yaxis let data = this.getdata() @@ -395,8 +767,8 @@ if (plot.pieshow !== 'value') { dv.transform({ type: 'percent', - field: Y_axis, - dimension: X_axis, + field: plot.Yaxis, + dimension: plot.Xaxis, as: 'percent' }) } @@ -445,8 +817,8 @@ .interval() .adjust('stack') .position('percent') - .color(X_axis) - .tooltip(X_axis + '*percent', (item, percent) => { + .color(plot.Xaxis) + .tooltip(plot.Xaxis + '*percent', (item, percent) => { percent = (percent * 100).toFixed(2) + '%' return { name: item, @@ -457,7 +829,7 @@ if (plot.label === 'true') { let setting = { content: (data) => { - return `${data[X_axis]}: ${(data.percent * 100).toFixed(2)}%` + return `${data[plot.Xaxis]}: ${(data.percent * 100).toFixed(2)}%` } } @@ -467,11 +839,6 @@ type: 'overlap' } setting.offset = 0 - // setting.style = { - // textAlign: 'center', - // fontSize: 12, - // fill: '#535353' - // } } _chart.label('percent', setting) @@ -481,9 +848,9 @@ let _chart = chart .interval() .adjust('stack') - .position(Y_axis) - .color(X_axis) - .tooltip(X_axis + '*' + Y_axis, (item, value) => { + .position(plot.Yaxis) + .color(plot.Xaxis) + .tooltip(plot.Xaxis + '*' + plot.Yaxis, (item, value) => { return { name: item, value: value @@ -493,7 +860,7 @@ if (plot.label === 'true') { let setting = { content: (data) => { - return `${data[X_axis]}: ${data[Y_axis]}` + return `${data[plot.Xaxis]}: ${data[plot.Yaxis]}` } } @@ -505,16 +872,26 @@ setting.offset = 0 } - _chart.label(Y_axis, setting) + _chart.label(plot.Yaxis, setting) } } chart.render() } + handleChange = (val) => { + this.setState({selectFields: val}, () => { + let _element = document.getElementById(this.state.chartId) + if (_element) { + _element.innerHTML = '' + } + this.viewrender() + }) + } + render() { const { plot, loading } = this.props - const { empty } = this.state + const { empty, chartFields, selectFields } = this.state return ( <div className="line-chart-plot-box"> @@ -525,6 +902,17 @@ <Spin /> </div> : null } + {plot.datatype === 'statistics' && chartFields.length > 0 ? <Select + mode="multiple" + showSearch + showArrow={true} + value={selectFields} + onChange={this.handleChange} + maxTagCount={0} + maxTagPlaceholder={(option) => <div className="type-label">{option.join('銆�')}</div>} + > + {chartFields.map((item, i) => <Select.Option key={i} value={item}>{item}</Select.Option>)} + </Select> : null} <div className={'canvas' + (empty ? ' empty' : '')} style={{minHeight: plot.height ? plot.height : 400}} id={this.state.chartId}></div> {empty ? <Empty description={false}/> : null} </div> -- Gitblit v1.8.0