import React, {Component} from 'react'
|
import PropTypes from 'prop-types'
|
import { is, fromJS } from 'immutable'
|
import { Chart } from '@antv/g2'
|
import DataSet from '@antv/data-set'
|
import { Spin, Empty, notification, Modal } from 'antd'
|
import { DownloadOutlined } from '@ant-design/icons'
|
import moment from 'moment'
|
|
import asyncComponent from './asyncButtonComponent'
|
import { chartColors } from '@/utils/option.js'
|
import Api from '@/api'
|
import Utils from '@/utils/utils.js'
|
import UtilsDM from '@/utils/utils-datamanage.js'
|
import MKEmitter from '@/utils/events.js'
|
import TimerTask from '@/utils/timer-task.js'
|
import NormalHeader from '@/tabviews/custom/components/share/normalheader'
|
import './index.scss'
|
|
// const NormalHeader = asyncComponent(() => import('@/tabviews/custom/components/share/normalheader'))
|
const ExcelOutButton = asyncComponent(() => import('@/tabviews/zshare/actionList/exceloutbutton'))
|
const ExcelInButton = asyncComponent(() => import('@/tabviews/zshare/actionList/excelInbutton'))
|
|
class LineChart extends Component {
|
static propTpyes = {
|
data: PropTypes.array, // 统一查询数据
|
config: PropTypes.object, // 组件配置信息
|
mainSearch: PropTypes.any, // 外层搜索条件
|
}
|
|
state = {
|
BID: '', // 主表ID
|
config: null, // 图表配置信息
|
empty: true, // 图表数据为空
|
loading: false, // 数据加载状态
|
chartId: Utils.getuuid(), // 图表Id
|
transfield: {}, // 字段名称翻译
|
sync: false, // 是否统一请求数据
|
plot: null, // 图表设置
|
search: null, // 搜索条件
|
vFields: [], // 数值字段
|
vstFields: null, // 统计数据值字段信息
|
chart: null
|
}
|
|
data = []
|
|
UNSAFE_componentWillMount () {
|
const { config, data, initdata } = this.props
|
let _config = fromJS(config).toJS()
|
let _sync = config.setting.sync === 'true'
|
|
let BID = ''
|
let BData = ''
|
|
if (config.setting.supModule) {
|
BData = window.GLOB.CacheData.get(config.setting.supModule)
|
} else {
|
BData = window.GLOB.CacheData.get(config.$pageId)
|
}
|
if (BData) {
|
BID = BData.$BID || ''
|
}
|
|
if (_sync && data) {
|
this.data = data[config.dataName] || []
|
_sync = false
|
} else if (_sync && initdata) {
|
this.data = initdata || []
|
_sync = false
|
}
|
|
let vFields = []
|
let vstFields = null
|
|
if (_config.plot.datatype === 'statistics') {
|
_config.plot.enabled = 'false'
|
let _column = _config.columns.filter(col => _config.plot.InfoValue === col.field)[0]
|
if (_column) {
|
let decimal = 0
|
|
if (/Decimal/ig.test(_column.datatype)) {
|
decimal = +_column.datatype.replace(/^Decimal\(18,/ig, '').replace(/\)/ig, '')
|
}
|
|
vstFields = {
|
label: _column.label,
|
field: _column.field,
|
show: _config.plot.show,
|
decimal
|
}
|
}
|
} else {
|
let _vFields = _config.plot.Yaxis && typeof(_config.plot.Yaxis) === 'string' ? [_config.plot.Yaxis] : _config.plot.Yaxis
|
_config.columns.forEach(col => {
|
if (_vFields.includes(col.field)) {
|
let decimal = 0
|
if (/Decimal/ig.test(col.datatype)) {
|
decimal = +col.datatype.replace(/^Decimal\(18,/ig, '').replace(/\)/ig, '')
|
}
|
vFields.push({
|
label: col.label,
|
field: col.field,
|
show: _config.plot.show,
|
decimal
|
})
|
}
|
})
|
}
|
|
_config.plot.height = Utils.getHeight(_config.plot.height)
|
_config.style.height = 'auto'
|
_config.style.minHeight = _config.plot.height + 30
|
|
if (_config.plot.title) {
|
_config.style.minHeight = _config.style.minHeight + 45
|
}
|
|
let transfield = {}
|
_config.columns.forEach(col => {
|
if (col.field) {
|
transfield[col.field] = col.label
|
}
|
})
|
|
_config.plot.color = _config.plot.color || 'rgba(0, 0, 0, 0.65)'
|
|
let bars = {}
|
if (_config.plot.enabled === 'true' && _config.plot.customs && _config.plot.customs.length > 0) {
|
let Bar_axis = []
|
_config.plot.customs = _config.plot.customs.map(item => {
|
item.name = transfield[item.type] || item.type
|
item.chartType = item.shape ? (item.shape[0] || 'bar') : 'bar'
|
item.shape = item.shape ? (item.shape[1] || '') : ''
|
|
if (item.chartType === 'bar') {
|
bars[item.type] = true
|
Bar_axis.push(item.type)
|
}
|
|
return item
|
})
|
|
_config.plot.hasBar = Bar_axis.length > 0
|
|
if (_config.plot.mutilBar !== 'overlap' && Bar_axis.length > 1) {
|
_config.plot.Bar_axis = Bar_axis
|
}
|
} else {
|
_config.plot.enabled = 'false'
|
}
|
|
let colors = new Map()
|
|
if (_config.plot.colors && _config.plot.colors.length > 0) { // 颜色设置
|
if (_config.plot.datatype === 'statistics') {
|
if (_config.plot.ramp === 'true') {
|
let _s = 'l(0) '
|
if (_config.plot.chartType === 'bar' || (_config.plot.chartType === 'line' && _config.plot.rampDirection === 'vertical')) {
|
_s = 'l(90) '
|
}
|
_config.plot.colors.forEach(item => {
|
if (!colors.has(item.type)) {
|
colors.set(item.type, _s + `0:${item.color} 1:${item.color1}`)
|
}
|
})
|
} else {
|
_config.plot.colors.forEach(item => {
|
if (!colors.has(item.type)) {
|
colors.set(item.type, item.color)
|
}
|
})
|
}
|
} else if (_config.plot.enabled === 'true') {
|
if (_config.plot.ramp === 'true') {
|
_config.plot.colors.forEach(item => {
|
let _type = transfield[item.type] || item.type
|
if (!colors.has(_type)) {
|
if (bars[item.type]) {
|
colors.set(_type, `l(90) 0:${item.color} 1:${item.color1}` )
|
} else {
|
colors.set(_type, `l(0) 0:${item.color} 1:${item.color1}` )
|
}
|
}
|
})
|
} else {
|
_config.plot.colors.forEach(item => {
|
let _type = transfield[item.type] || item.type
|
if (!colors.has(_type)) {
|
colors.set(_type, item.color)
|
}
|
})
|
}
|
} else {
|
if (_config.plot.ramp === 'true') {
|
let _s = 'l(0) '
|
if (_config.plot.chartType === 'bar' || (_config.plot.chartType === 'line' && _config.plot.rampDirection === 'vertical')) {
|
_s = 'l(90) '
|
}
|
_config.plot.colors.forEach(item => {
|
if (!transfield[item.type]) return
|
if (!colors.has(transfield[item.type])) {
|
colors.set(transfield[item.type], _s + `0:${item.color} 1:${item.color1}` )
|
}
|
})
|
} else {
|
_config.plot.colors.forEach(item => {
|
if (!transfield[item.type]) return
|
if (!colors.has(transfield[item.type])) {
|
colors.set(transfield[item.type], item.color)
|
}
|
})
|
}
|
}
|
_config.plot.$colors = colors
|
}
|
|
let limit = _config.plot.XLimit || 11
|
|
let xc = {label: {
|
formatter: (val) => {
|
if (!val || /^\s*$/.test(val)) return val
|
let _val = `${val}`
|
if (_val.length <= limit) return val
|
return _val.substring(0, limit) + '...'
|
},
|
style: { fill: _config.plot.color }
|
}}
|
let yc = {label: { style: { fill: _config.plot.color } }}
|
if (_config.plot.grid === 'hidden') {
|
yc.grid = null
|
}
|
if (_config.plot.y_line === 'show') {
|
yc.line = {style: { stroke: '#D1D2CE' }}
|
}
|
if (_config.plot.lineColor) {
|
xc.tickLine = {style: { stroke: _config.plot.lineColor }}
|
xc.line = { style: { stroke: _config.plot.lineColor } }
|
if (yc.grid !== null) {
|
yc.grid = { line: { style: { stroke: _config.plot.lineColor } }}
|
}
|
if (yc.line) {
|
yc.line = { style: { stroke: _config.plot.lineColor } }
|
}
|
}
|
|
_config.plot.$xc = xc
|
_config.plot.$yc = yc
|
|
_config.plot.$paddingLeft = 30
|
_config.plot.$paddingRight = 30
|
|
if (_config.plot.enabled === 'true') {
|
let colorIndex = 0
|
let limit = chartColors.length
|
let axisIndex = 0
|
let fields = []
|
let legends = []
|
let vFieldsShow = {}
|
|
_config.plot.customs.forEach(item => {
|
if (colors.has(item.name)) {
|
item.color = colors.get(item.name)
|
} else {
|
item.color = chartColors[colorIndex % limit]
|
colorIndex++
|
}
|
|
if (item.axis === 'true' && axisIndex < 2) {
|
if (axisIndex === 0) {
|
item.axis = { label: {style: { fill: _config.plot.color }} }
|
if (item.title !== 'false') {
|
item.axis.title = { style: { fill: _config.plot.color } }
|
_config.plot.$paddingLeft = 50
|
}
|
if (_config.plot.grid === 'hidden') {
|
item.axis.grid = null
|
}
|
if (_config.plot.y_line === 'show') {
|
item.axis.line = {style: { stroke: '#D1D2CE' }}
|
}
|
if (_config.plot.lineColor) {
|
if (item.axis.grid !== null) {
|
item.axis.grid = { line: { style: { stroke: _config.plot.lineColor } }}
|
}
|
if (item.axis.line) {
|
item.axis.line = { style: { stroke: _config.plot.lineColor } }
|
}
|
}
|
fields.unshift(item)
|
} else {
|
item.axis = { grid: null, label: {style: { fill: _config.plot.color }} }
|
if (item.title !== 'false') {
|
item.axis.title = { style: { fill: _config.plot.color } }
|
_config.plot.$paddingRight = 60
|
}
|
if (_config.plot.y_line === 'show') {
|
item.axis.line = {style: { stroke: '#D1D2CE' }}
|
}
|
if (_config.plot.lineColor && item.axis.line) {
|
item.axis.line = { style: { stroke: _config.plot.lineColor } }
|
}
|
fields.splice(1, 0, item)
|
}
|
axisIndex++
|
} else {
|
item.axis = { grid: null, title: null, label: null }
|
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 } }
|
})
|
|
if (!_config.plot.Bar_axis || item.chartType !== 'bar') { // 折线图或重叠下的柱状图可单独设置显示类型
|
if (item.show) {
|
vFieldsShow[item.type] = item.show
|
} else {
|
item.show = _config.plot.show
|
}
|
}
|
})
|
_config.plot.customs = fields
|
_config.plot.legends = legends
|
_config.plot.axisIndex = axisIndex
|
vFields.forEach(item => {
|
if (vFieldsShow[item.field]) {
|
item.show = vFieldsShow[item.field]
|
}
|
})
|
}
|
|
this.setState({
|
config: _config,
|
BID: BID || '',
|
vFields: vFields,
|
vstFields: vstFields,
|
arr_field: _config.columns.map(col => col.field).join(','),
|
plot: _config.plot,
|
sync: _sync,
|
search: Utils.initMainSearch(config.search),
|
transfield
|
}, () => {
|
if (config.setting.sync !== 'true' && config.setting.onload === 'true') {
|
setTimeout(() => {
|
this.loadData()
|
}, _config.setting.delay || 0)
|
}
|
})
|
|
if (this.data.length > 0) {
|
this.handleData()
|
}
|
}
|
|
/**
|
* @description 图表数据更新,刷新内容
|
*/
|
UNSAFE_componentWillReceiveProps (nextProps) {
|
const { sync, config } = this.state
|
|
if (sync && !is(fromJS(this.props.data), fromJS(nextProps.data))) {
|
let _data = []
|
if (nextProps.data && nextProps.data[config.dataName]) {
|
_data = nextProps.data[config.dataName] || []
|
}
|
|
if (!is(fromJS(this.data), fromJS(_data))) {
|
this.data = _data
|
this.handleData()
|
}
|
|
this.setState({sync: false})
|
} else if (config.setting.useMSearch && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
|
this.setState({}, () => {
|
this.loadData()
|
})
|
}
|
}
|
|
shouldComponentUpdate (nextProps, nextState) {
|
return !is(fromJS(this.state), fromJS(nextState))
|
}
|
|
componentDidMount () {
|
const { config, sync } = this.state
|
|
MKEmitter.addListener('reloadData', this.reloadData)
|
MKEmitter.addListener('resetSelectLine', this.resetParentParam)
|
MKEmitter.addListener('queryModuleParam', this.queryModuleParam)
|
MKEmitter.addListener('refreshByButtonResult', this.refreshByButtonResult)
|
|
if (config.timer) {
|
this.timer = new TimerTask()
|
this.timer.init(config.uuid, config.timer, config.timerRepeats, () => {
|
this.loadData(true)
|
})
|
}
|
|
if (config.$cache && (config.setting.sync !== 'true' || sync)) {
|
Api.getLCacheConfig(config.uuid).then(res => {
|
if (!res || this.data.length > 0) return
|
|
if (!is(fromJS(this.data), fromJS(res))) {
|
this.data = res
|
this.handleData()
|
}
|
})
|
}
|
}
|
|
/**
|
* @description 组件销毁,清除state更新,清除快捷键设置
|
*/
|
componentWillUnmount () {
|
this.setState = () => {
|
return
|
}
|
MKEmitter.removeListener('reloadData', this.reloadData)
|
MKEmitter.removeListener('resetSelectLine', this.resetParentParam)
|
MKEmitter.removeListener('queryModuleParam', this.queryModuleParam)
|
MKEmitter.removeListener('refreshByButtonResult', this.refreshByButtonResult)
|
|
this.timer && this.timer.stop()
|
}
|
|
/**
|
* @description 按钮执行完成后页面刷新
|
* @param {*} menuId // 菜单Id
|
* @param {*} position // 刷新位置
|
* @param {*} btn // 执行的按钮
|
*/
|
refreshByButtonResult = (menuId, position, btn) => {
|
const { config, BID } = this.state
|
|
if (config.uuid !== menuId) return
|
|
if ((position === 'mainline' || position === 'popclose') && config.setting.supModule && BID) { // 刷新源组件时,附带刷新上级行与当前组件
|
MKEmitter.emit('reloadData', config.setting.supModule, BID)
|
} else {
|
this.loadData()
|
}
|
|
if (position === 'popclose') { // 执行启动弹窗的按钮所选择的刷新项
|
btn.$tabId && MKEmitter.emit('refreshPopButton', btn.$tabId)
|
}
|
}
|
|
reloadData = (menuId) => {
|
const { config } = this.state
|
|
if (config.uuid !== menuId) return
|
|
this.loadData()
|
}
|
|
resetParentParam = (MenuID, id) => {
|
const { config } = this.state
|
|
if (!config.setting.supModule || config.setting.supModule !== MenuID) return
|
if (id !== this.state.BID || id !== '') {
|
this.setState({ BID: id }, () => {
|
this.loadData()
|
})
|
}
|
}
|
|
/**
|
* @description 导出Excel时,获取页面搜索排序等参数
|
*/
|
queryModuleParam = (menuId, callback) => {
|
const { mainSearch } = this.props
|
const { arr_field, config, search } = this.state
|
|
if (config.uuid !== menuId) return
|
|
let searches = search ? fromJS(search).toJS() : []
|
if (config.setting.useMSearch && mainSearch && mainSearch.length > 0) { // 主表搜索条件
|
let keys = searches.map(item => item.key.toLowerCase())
|
mainSearch.forEach(item => {
|
if (!keys.includes(item.key.toLowerCase())) {
|
searches.push(item)
|
}
|
})
|
}
|
|
callback({
|
arr_field: arr_field,
|
orderBy: config.setting.order || '',
|
search: searches,
|
menuName: config.name
|
})
|
}
|
|
/**
|
* @description 数据加载
|
*/
|
async loadData (hastimer) {
|
const { mainSearch } = this.props
|
const { config, arr_field, BID, search } = this.state
|
|
if (config.setting.supModule && !BID) { // BID 不存在时,不做查询
|
if (!is(fromJS(this.data), fromJS([]))) {
|
this.data = []
|
this.handleData()
|
}
|
return
|
}
|
|
let searches = search ? fromJS(search).toJS() : []
|
if (config.setting.useMSearch && mainSearch && mainSearch.length > 0) { // 主表搜索条件
|
let keys = searches.map(item => item.key)
|
mainSearch.forEach(item => {
|
if (!keys.includes(item.key)) {
|
searches.push(item)
|
}
|
})
|
}
|
|
let requireFields = searches.filter(item => item.required && item.value === '')
|
if (requireFields.length > 0) {
|
return
|
}
|
|
if (!hastimer) {
|
this.setState({
|
loading: true
|
})
|
}
|
|
let _orderBy = config.setting.order || ''
|
let param = UtilsDM.getQueryDataParams(config.setting, arr_field, searches, _orderBy, '', '', BID)
|
|
let result = await Api.genericInterface(param)
|
if (result.status) {
|
if (config.$cache && config.setting.onload !== 'false') {
|
Api.writeCacheConfig(config.uuid, result.data || '')
|
}
|
|
this.setState({
|
loading: false
|
})
|
|
if (!is(fromJS(this.data), fromJS(result.data || []))) {
|
this.data = result.data || []
|
this.handleData()
|
}
|
|
if (config.timer && config.clearField && result.data && result.data[0]) {
|
let vals = (config.clearValue || '').split(',')
|
if (vals.includes(result.data[0][config.clearField])) {
|
this.timer && this.timer.stop()
|
}
|
}
|
} else {
|
this.setState({
|
loading: false
|
})
|
this.timer && this.timer.stop()
|
|
if (result.ErrCode === 'N') {
|
Modal.error({
|
title: result.message,
|
})
|
} else {
|
notification.error({
|
top: 92,
|
message: result.message,
|
duration: 10
|
})
|
}
|
}
|
}
|
|
/**
|
* @description 数据预处理,统计数据需要重置
|
*/
|
handleData = () => {
|
let _element = document.getElementById(this.state.chartId)
|
if (_element) {
|
_element.innerHTML = ''
|
}
|
setTimeout(() => {
|
this.viewrender()
|
}, 100)
|
}
|
|
/**
|
* @description 图表数据预处理
|
* 1、通过显示列进行数据类型转换
|
* 2、重复数据:取平均值、累计、去重
|
* 3、柱状图数据补齐
|
*/
|
getdata = () => {
|
const { plot, vFields, config } = this.state
|
|
if (this.data.length === 0) {
|
this.setState({empty: true})
|
return []
|
}
|
|
let _data = []
|
let _cdata = fromJS(this.data).toJS()
|
|
if (plot.repeat === 'average') {
|
let _mdata = new Map()
|
_cdata.forEach(item => {
|
if (!item[plot.Xaxis] && item[plot.Xaxis] !== 0) return
|
|
vFields.forEach(col => {
|
if (typeof(item[col.field]) !== 'number') {
|
item[col.field] = parseFloat(item[col.field])
|
if (isNaN(item[col.field])) {
|
item[col.field] = 0
|
}
|
}
|
if (col.show === 'percent') {
|
item[col.field] = item[col.field] * 100
|
}
|
})
|
|
// dodge is not support linear attribute, please use category attribute! 时间格式
|
if (/^\d{4}-\d{2}-\d{2}(\s\d{2}:\d{2}:\d{2})?/.test(item[plot.Xaxis])) {
|
item[plot.Xaxis] = ' ' + item[plot.Xaxis]
|
} else {
|
item[plot.Xaxis] = '' + item[plot.Xaxis]
|
}
|
|
if (!_mdata.has(item[plot.Xaxis])) {
|
item.$count = 1
|
_mdata.set(item[plot.Xaxis], item)
|
} else {
|
let _item = _mdata.get(item[plot.Xaxis])
|
_item.$count++
|
vFields.forEach(col => {
|
_item[col.field] += item[col.field]
|
})
|
_mdata.set(item[plot.Xaxis], _item)
|
}
|
})
|
|
_data = [..._mdata.values()]
|
_data = _data.map(item => {
|
vFields.forEach(col => {
|
item[col.field] = item[col.field] / item.$count
|
item[col.field] = item[col.field].toFixed(col.decimal)
|
item[col.field] = +item[col.field]
|
})
|
item.$$uuid = item[config.setting.primaryKey] || ''
|
return item
|
})
|
} else if (plot.repeat === 'cumsum') {
|
let _mdata = new Map()
|
_cdata.forEach(item => {
|
if (!item[plot.Xaxis] && item[plot.Xaxis] !== 0) return
|
|
vFields.forEach(col => {
|
if (typeof(item[col.field]) !== 'number') {
|
item[col.field] = parseFloat(item[col.field])
|
if (isNaN(item[col.field])) {
|
item[col.field] = 0
|
}
|
}
|
if (col.show === 'percent') {
|
item[col.field] = item[col.field] * 100
|
}
|
})
|
|
if (/^\d{4}-\d{2}-\d{2}(\s\d{2}:\d{2}:\d{2})?/.test(item[plot.Xaxis])) {
|
item[plot.Xaxis] = ' ' + item[plot.Xaxis]
|
} else {
|
item[plot.Xaxis] = '' + item[plot.Xaxis]
|
}
|
|
if (!_mdata.has(item[plot.Xaxis])) {
|
_mdata.set(item[plot.Xaxis], item)
|
} else {
|
let _item = _mdata.get(item[plot.Xaxis])
|
vFields.forEach(col => {
|
_item[col.field] += item[col.field]
|
})
|
_mdata.set(item[plot.Xaxis], _item)
|
}
|
})
|
|
_data = [..._mdata.values()]
|
_data = _data.map(item => {
|
vFields.forEach(col => {
|
item[col.field] = item[col.field].toFixed(col.decimal)
|
item[col.field] = +item[col.field]
|
})
|
item.$$uuid = item[config.setting.primaryKey] || ''
|
return item
|
})
|
} else { // plot.repeat === 'unrepeat'
|
let _mdata = new Map()
|
_cdata.forEach(item => {
|
if (!item[plot.Xaxis] && item[plot.Xaxis] !== 0) return
|
|
if (/^\d{4}-\d{2}-\d{2}(\s\d{2}:\d{2}:\d{2})?/.test(item[plot.Xaxis])) {
|
item[plot.Xaxis] = ' ' + item[plot.Xaxis]
|
} else {
|
item[plot.Xaxis] = '' + item[plot.Xaxis]
|
}
|
|
if (!_mdata.has(item[plot.Xaxis])) {
|
vFields.forEach(col => {
|
if (typeof(item[col.field]) !== 'number') {
|
item[col.field] = parseFloat(item[col.field])
|
if (isNaN(item[col.field])) {
|
item[col.field] = 0
|
}
|
}
|
if (col.show === 'percent') {
|
item[col.field] = item[col.field] * 100
|
}
|
item[col.field] = item[col.field].toFixed(col.decimal)
|
item[col.field] = +item[col.field]
|
})
|
|
item.$$uuid = item[config.setting.primaryKey] || ''
|
_mdata.set(item[plot.Xaxis], item)
|
}
|
})
|
|
_data = [..._mdata.values()]
|
}
|
|
this.setState({empty: _data.length === 0})
|
return _data
|
}
|
|
/**
|
* @description 统计数据预处理
|
*/
|
getStaticMsg = () => {
|
const { plot, vstFields } = this.state
|
|
let percent = false
|
let decimal = vstFields ? vstFields.decimal : 0
|
|
if (plot.show === 'percent') {
|
percent = true
|
}
|
|
if (this.data.length === 0) {
|
this.setState({empty: true})
|
return []
|
}
|
|
let _data = []
|
let _cdata = fromJS(this.data).toJS()
|
|
if (plot.repeat === 'average') {
|
let _mdata = new Map()
|
_cdata.forEach(item => {
|
if (!item[plot.InfoType] || !item[plot.Xaxis]) return
|
|
if (/^\d{4}-\d{2}-\d{2}(\s\d{2}:\d{2}:\d{2})?/.test(item[plot.Xaxis])) {
|
item[plot.Xaxis] = ' ' + item[plot.Xaxis]
|
}
|
|
item.$uuid = item[plot.InfoType] + item[plot.Xaxis]
|
if (typeof(item[plot.InfoValue]) !== 'number') {
|
item[plot.InfoValue] = parseFloat(item[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
|
|
if (/^\d{4}-\d{2}-\d{2}(\s\d{2}:\d{2}:\d{2})?/.test(item[plot.Xaxis])) {
|
item[plot.Xaxis] = ' ' + item[plot.Xaxis]
|
}
|
|
item.$uuid = item[plot.InfoType] + item[plot.Xaxis]
|
|
if (typeof(item[plot.InfoValue]) !== 'number') {
|
item[plot.InfoValue] = parseFloat(item[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
|
|
if (/^\d{4}-\d{2}-\d{2}(\s\d{2}:\d{2}:\d{2})?/.test(item[plot.Xaxis])) {
|
item[plot.Xaxis] = ' ' + item[plot.Xaxis]
|
}
|
|
item.$uuid = item[plot.InfoType] + item[plot.Xaxis]
|
|
if (!_mdata.has(item.$uuid)) {
|
if (typeof(item[plot.InfoValue]) !== 'number') {
|
item[plot.InfoValue] = parseFloat(item[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()]
|
}
|
|
this.setState({empty: _data.length === 0})
|
|
return _data
|
}
|
|
/**
|
* @description 图表渲染分组
|
*/
|
viewrender = () => {
|
const { plot } = this.state
|
|
if (plot.chartType === 'line') {
|
this.linerender()
|
} else if (plot.chartType === 'bar') {
|
this.barrender()
|
}
|
}
|
|
/**
|
* @description 折线图渲染
|
*/
|
linerender = () => {
|
const { plot, transfield } = this.state
|
|
let _data = []
|
let _valfield = 'value'
|
let _typefield = 'key'
|
let colorIndex = 0
|
|
if (plot.datatype === 'statistics') {
|
_valfield = plot.InfoValue
|
_typefield = plot.InfoType
|
|
_data = this.getStaticMsg()
|
} else {
|
let data = this.getdata()
|
|
if (plot.enabled === 'true') {
|
this.customrender(data)
|
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({
|
container: this.state.chartId,
|
autoFit: true,
|
height: plot.height
|
})
|
|
chart.data(_data)
|
|
if (plot.coordinate !== 'polar') {
|
chart.scale(plot.Xaxis, {
|
range: [0, 1]
|
})
|
}
|
|
let c = {
|
nice: true,
|
range: [0, 0.9]
|
}
|
|
if (plot.min || plot.min === 0) {
|
c.min = plot.min
|
}
|
if (plot.max || plot.max === 0) {
|
c.max = plot.max
|
}
|
chart.scale(_valfield, c)
|
|
chart.axis(plot.Xaxis, plot.$xc)
|
chart.axis(_valfield, plot.$yc)
|
|
if (!plot.legend || plot.legend === 'hidden') {
|
chart.legend(false)
|
} else {
|
chart.legend({
|
position: plot.legend,
|
itemName: { style: { fill: plot.color } }
|
})
|
}
|
|
if (plot.tooltip !== 'true') {
|
chart.tooltip(false)
|
} else {
|
chart.tooltip({
|
shared: true
|
})
|
}
|
|
if (plot.transpose === 'true') {
|
chart.coordinate().transpose()
|
}
|
|
if (plot.coordinate === 'polar') {
|
chart.coordinate('polar', {
|
innerRadius: 0.1,
|
radius: 0.8
|
})
|
}
|
|
let _chart = chart
|
.line()
|
.position(`${plot.Xaxis}*${_valfield}`)
|
.shape(plot.shape || 'smooth')
|
.tooltip(`${plot.Xaxis}*${_valfield}*${_typefield}`, (name, value, type) => {
|
return {
|
name: type,
|
value: plot.show === 'percent' ? value + '%' : value
|
}
|
})
|
|
if (plot.$colors) {
|
let limit = chartColors.length
|
_chart.color(_typefield, (key) => {
|
if (plot.$colors.has(key)) {
|
if (plot.area === 'true' && plot.rampDirection === 'vertical') {
|
return plot.$colors.get(key).replace(/l\(9?0\) 0:|\s1:.*/ig, '')
|
}
|
return plot.$colors.get(key)
|
} else {
|
colorIndex++
|
return chartColors[(colorIndex - 1) % limit]
|
}
|
})
|
} else {
|
_chart.color(_typefield)
|
}
|
if (plot.label !== 'false') {
|
_chart.label(_valfield, (value) => {
|
if (plot.labelValue === 'zero' && value === 0) {
|
return null
|
}
|
if (plot.show === 'percent') {
|
value = value + '%'
|
}
|
return {
|
content: value,
|
style: {
|
fill: plot.color
|
}
|
}
|
})
|
}
|
|
if (plot.point === 'true') {
|
let _chart = chart
|
.point()
|
.position(`${plot.Xaxis}*${_valfield}`)
|
.size(3)
|
.shape('circle')
|
|
if (plot.$colors) {
|
let limit = chartColors.length
|
_chart.color(_typefield, (key) => {
|
if (plot.$colors.has(key)) {
|
return plot.$colors.get(key)
|
} else {
|
colorIndex++
|
return chartColors[(colorIndex - 1) % limit]
|
}
|
})
|
} else {
|
_chart.color(_typefield)
|
}
|
}
|
|
if (plot.area === 'true') {
|
let area = chart
|
.area()
|
// .shape(plot.shape || 'smooth')
|
.position(`${plot.Xaxis}*${_valfield}`)
|
.tooltip(false)
|
|
if (plot.shape === 'smooth') {
|
area.shape('smooth')
|
}
|
if (plot.$colors) {
|
let limit = chartColors.length
|
area.color(_typefield, (key) => {
|
if (plot.$colors.has(key)) {
|
return plot.$colors.get(key)
|
} else {
|
colorIndex++
|
return chartColors[(colorIndex - 1) % limit]
|
}
|
})
|
} else {
|
area.color(_typefield)
|
}
|
}
|
|
if (plot.interaction && plot.interaction.length) {
|
plot.interaction.forEach(t => {
|
chart.interaction(t)
|
})
|
}
|
|
chart.render()
|
|
this.setState({chart})
|
}
|
|
/**
|
* @description 自定义渲染
|
*/
|
customrender = (data) => {
|
const { plot, transfield } = this.state
|
const ds = new DataSet()
|
const dv = ds.createView().source(data)
|
|
dv.transform({
|
type: 'map',
|
callback(row) {
|
plot.customs.forEach(line => {
|
row[line.name] = row[line.type]
|
})
|
return row
|
}
|
})
|
|
let padding = [10, 30, 30, 30]
|
|
if (!plot.Bar_axis) {
|
padding = [10, plot.$paddingRight, 30, plot.$paddingLeft]
|
}
|
|
const chart = new Chart({
|
container: this.state.chartId,
|
autoFit: true,
|
height: plot.height
|
})
|
|
// 坐标轴格式化
|
chart.axis(plot.Xaxis, plot.$xc)
|
|
if (!plot.hasBar) {
|
chart.scale(plot.Xaxis, {
|
range: [0, 1]
|
})
|
}
|
|
if (!plot.legend || plot.legend === 'hidden') {
|
chart.legend(false)
|
} else {
|
chart.legend({
|
custom: true,
|
position: plot.legend,
|
items: plot.legends,
|
itemName: { style: { fill: plot.color } }
|
})
|
}
|
|
if (plot.tooltip !== 'true') {
|
chart.tooltip(false)
|
} else {
|
chart.tooltip({
|
shared: true
|
})
|
}
|
|
chart.scale({
|
nice: true
|
})
|
|
let lablecfg = {
|
position: 'top',
|
offset: 2,
|
style: {
|
fill: '#fff'
|
}
|
}
|
|
if (plot.label === 'top') {
|
lablecfg.offset = -5
|
lablecfg.style.textBaseline = 'top'
|
} else if (plot.label === 'middle') {
|
lablecfg.position = 'middle'
|
lablecfg.offset = 0
|
} else if (plot.label === 'bottom') {
|
lablecfg.position = 'bottom'
|
lablecfg.offset = 0
|
} else if (plot.label === 'true') {
|
lablecfg.style.fill = plot.color
|
}
|
|
if (plot.Bar_axis) {
|
const view1 = chart.createView({
|
region: {
|
start: { x: 0, y: 0 },
|
end: { x: 1, y: 1 }
|
},
|
padding
|
})
|
const dst = new DataSet()
|
const dvt = dst.createView().source(data)
|
|
dvt.transform({
|
type: 'fold',
|
fields: [...plot.Bar_axis],
|
key: 'key',
|
value: 'value'
|
})
|
|
dvt.transform({
|
type: 'map',
|
callback(row) {
|
row.key = transfield[row.key] || row.key
|
return row
|
},
|
})
|
|
view1.data(dvt.rows)
|
|
let c = {
|
nice: true,
|
range: [0, 0.9]
|
}
|
|
if (plot.min || plot.min === 0) {
|
c.min = plot.min
|
}
|
if (plot.max || plot.max === 0) {
|
c.max = plot.max
|
}
|
view1.scale('value', c)
|
view1.axis('value', plot.$yc)
|
|
// view1.legend(false)
|
|
let colorIndex = 0
|
|
if (plot.adjust !== 'stack') {
|
let _chart = view1
|
.interval()
|
.position(`${plot.Xaxis}*value`)
|
.adjust([
|
{
|
type: 'dodge',
|
marginRatio: 0
|
}
|
])
|
.shape(plot.shape || 'rect')
|
.tooltip(`${plot.Xaxis}*value*key`, (name, value, key) => {
|
if (plot.show === 'percent') {
|
value = value + '%'
|
}
|
return {
|
name: key,
|
value: value
|
}
|
})
|
|
if (plot.$colors) {
|
let limit = chartColors.length
|
_chart.color('key', (key) => {
|
if (plot.$colors.has(key)) {
|
return plot.$colors.get(key)
|
} else {
|
colorIndex++
|
return chartColors[(colorIndex - 1) % limit]
|
}
|
})
|
} else {
|
_chart.color('key')
|
}
|
if (plot.label !== 'false') {
|
_chart.label('value*key', (value, key) => {
|
if (plot.labelValue === 'zero' && value === 0) {
|
return null
|
}
|
|
if (plot.show === 'percent') {
|
value = value + '%'
|
}
|
|
if (plot.label === 'true' && plot.labelColor === 'custom' && plot.$colors && plot.$colors.has(key)) {
|
lablecfg.style.fill = plot.$colors.get(key)
|
}
|
return {
|
content: value,
|
...lablecfg
|
}
|
})
|
}
|
|
if (plot.barSize || plot.correction) {
|
_chart.size(plot.barSize || 35)
|
}
|
if (plot.barRadius) {
|
_chart.style({ radius: [plot.barRadius, plot.barRadius, 0, 0] })
|
}
|
} else if (plot.adjust === 'stack') {
|
let _chart = view1
|
.interval()
|
.position(`${plot.Xaxis}*value`)
|
.adjust('stack')
|
.shape(plot.shape || 'rect')
|
.tooltip(`${plot.Xaxis}*value*key`, (name, value, type) => {
|
if (plot.show === 'percent') {
|
value = value + '%'
|
}
|
return {
|
name: type,
|
value: value
|
}
|
})
|
|
if (plot.$colors) {
|
let limit = chartColors.length
|
_chart.color('key', (key) => {
|
if (plot.$colors.has(key)) {
|
return plot.$colors.get(key)
|
} else {
|
colorIndex++
|
return chartColors[(colorIndex - 1) % limit]
|
}
|
})
|
} else {
|
_chart.color('key')
|
}
|
if (plot.label !== 'false') {
|
_chart.label('value*key', (value, key) => {
|
if (plot.labelValue === 'zero' && value === 0) {
|
return null
|
}
|
|
if (plot.show === 'percent') {
|
value = value + '%'
|
}
|
if (plot.label === 'true' && plot.labelColor === 'custom' && plot.$colors && plot.$colors.has(key)) {
|
lablecfg.style.fill = plot.$colors.get(key)
|
}
|
return {
|
content: value,
|
...lablecfg
|
}
|
})
|
}
|
|
if (plot.barSize || plot.correction) {
|
_chart.size(plot.barSize || 35)
|
}
|
if (plot.barRadius) {
|
_chart.style({ radius: [plot.barRadius, plot.barRadius, 0, 0] })
|
}
|
}
|
}
|
|
let view2 = chart
|
|
if (plot.Bar_axis) {
|
view2 = chart.createView({
|
region: {
|
start: { x: 0, y: 0 },
|
end: { x: 1, y: 1 }
|
},
|
padding
|
})
|
}
|
|
view2.data(dv.rows)
|
// view2.legend(false)
|
|
plot.customs.forEach(item => {
|
if (item.chartType === 'bar' && !plot.Bar_axis) {
|
view2.axis(item.name, item.axis)
|
|
let c = {
|
nice: true,
|
range: [0, 0.9]
|
}
|
|
if (item.min || item.min === 0) {
|
c.min = item.min
|
}
|
if (item.max || item.max === 0) {
|
c.max = item.max
|
}
|
|
view2.scale(item.name, c)
|
let _chart = view2
|
.interval()
|
.position(`${plot.Xaxis}*${item.name}`)
|
.color(item.color)
|
.shape(item.shape)
|
.tooltip(`${item.name}`, (value) => {
|
return {
|
name: item.name,
|
value: item.show === 'percent' ? value + '%' : value
|
}
|
})
|
|
if (plot.barSize) {
|
_chart.size(plot.barSize || 35)
|
}
|
if (item.label !== 'false') {
|
_chart.label(item.name, (value) => {
|
if (plot.labelValue === 'zero' && value === 0) {
|
return null
|
}
|
|
if (item.show === 'percent') {
|
value = value + '%'
|
}
|
if (plot.label === 'true' && plot.labelColor === 'custom' && item.color) {
|
lablecfg.style.fill = item.color
|
}
|
return {
|
content: value,
|
...lablecfg
|
}
|
})
|
}
|
if (plot.barRadius) {
|
_chart.style({ radius: [plot.barRadius, plot.barRadius, 0, 0] })
|
}
|
} else if (item.chartType === 'line') {
|
if (!plot.Bar_axis) {
|
view2.axis(item.name, item.axis)
|
} else {
|
view2.axis(item.name, { grid: null, title: null, label: null })
|
}
|
let c = {
|
nice: true,
|
range: [0, 0.9]
|
}
|
|
if (item.min || item.min === 0) {
|
c.min = item.min
|
}
|
if (item.max || item.max === 0) {
|
c.max = item.max
|
}
|
|
view2.scale(item.name, c)
|
let _chart = view2
|
.line()
|
.position(`${plot.Xaxis}*${item.name}`)
|
.color(item.color)
|
.shape(item.shape)
|
.tooltip(`${item.name}`, (value) => {
|
return {
|
name: item.name,
|
value: item.show === 'percent' ? value + '%' : value
|
}
|
})
|
|
if (item.label === 'true') {
|
_chart.label(item.name, (value) => {
|
if (plot.labelValue === 'zero' && value === 0) {
|
return null
|
}
|
|
if (item.show === 'percent') {
|
value = value + '%'
|
}
|
return {
|
content: value,
|
style: {
|
fill: plot.color
|
}
|
}
|
})
|
}
|
|
if (plot.point === 'true') {
|
chart
|
.point()
|
.position(`${plot.Xaxis}*${item.name}`)
|
.color(item.color)
|
.size(3)
|
.shape('circle')
|
}
|
}
|
})
|
|
if (plot.interaction && plot.interaction.length) {
|
plot.interaction.forEach(t => {
|
if (t === 'element-active' || t === 'element-highlight') {
|
chart.interaction(t)
|
}
|
})
|
}
|
|
chart.render()
|
|
this.setState({chart})
|
}
|
|
/**
|
* @description 柱状图渲染
|
*/
|
barrender = () => {
|
const { plot, transfield, config } = this.state
|
|
let _data = []
|
let _valfield = 'value'
|
let _typefield = 'key'
|
let colorIndex = 0
|
let barcolors = {}
|
|
if (plot.datatype === 'statistics') {
|
_valfield = plot.InfoValue
|
_typefield = plot.InfoType
|
|
_data = this.getStaticMsg()
|
} else {
|
let data = this.getdata()
|
|
if (plot.enabled === 'true') {
|
this.customrender(data)
|
return
|
}
|
|
if (plot.barcolors && plot.barcolors.length > 0 && plot.Yaxis.length === 1) {
|
data.forEach((item, i) => {
|
if (plot.barcolors[i]) {
|
barcolors[item[plot.Xaxis]] = plot.barcolors[i].color
|
}
|
})
|
} else {
|
barcolors = null
|
}
|
|
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
|
})
|
|
chart.data(_data)
|
|
let c = {
|
nice: true,
|
range: [0, 0.9]
|
}
|
|
if (plot.min || plot.min === 0) {
|
c.min = plot.min
|
}
|
if (plot.max || plot.max === 0) {
|
c.max = plot.max
|
}
|
chart.scale(_valfield, c)
|
|
chart.axis(plot.Xaxis, plot.$xc)
|
chart.axis(_valfield, plot.$yc)
|
|
if (!plot.legend || plot.legend === 'hidden') {
|
chart.legend(false)
|
} else {
|
chart.legend({
|
position: plot.legend,
|
itemName: { style: { fill: plot.color } }
|
})
|
}
|
|
if (plot.tooltip !== 'true') {
|
chart.tooltip(false)
|
} else {
|
chart.tooltip({
|
showMarkers: false,
|
shared: true
|
})
|
}
|
|
let lablecfg = {
|
position: 'top',
|
offset: 2,
|
style: {
|
fill: '#fff'
|
}
|
}
|
|
if (plot.label === 'top') {
|
lablecfg.offset = -5
|
lablecfg.style.textBaseline = 'top'
|
} else if (plot.label === 'middle') {
|
lablecfg.position = 'middle'
|
lablecfg.offset = 0
|
} else if (plot.label === 'bottom') {
|
lablecfg.position = 'bottom'
|
lablecfg.offset = 0
|
} else if (plot.label === 'true') {
|
lablecfg.style.fill = plot.color
|
}
|
|
if (plot.transpose === 'true') {
|
chart.coordinate().transpose()
|
if (plot.label === 'top') {
|
delete lablecfg.style.textBaseline
|
lablecfg.position = 'right'
|
lablecfg.offset = -3
|
lablecfg.style.textAlign = 'end'
|
} else if (plot.label === 'middle') {
|
lablecfg.position = 'middle'
|
lablecfg.offset = 0
|
} else if (plot.label === 'bottom') {
|
lablecfg.position = 'left'
|
lablecfg.offset = 2
|
} else if (plot.label === 'true') {
|
lablecfg.position = 'right'
|
lablecfg.offset = 2
|
}
|
}
|
|
if (plot.coordinate === 'polar') {
|
chart.coordinate('polar', {
|
innerRadius: 0.1,
|
radius: 0.8
|
})
|
}
|
|
if (plot.adjust !== 'stack') {
|
let _chart = chart
|
.interval()
|
.position(`${plot.Xaxis}*${_valfield}`)
|
.adjust([
|
{
|
type: 'dodge',
|
marginRatio: 0
|
}
|
])
|
.shape(plot.shape || 'rect')
|
.tooltip(`${plot.Xaxis}*${_valfield}*${_typefield}`, (name, value, type) => {
|
return {
|
name: type,
|
value: plot.show === 'percent' ? value + '%' : value
|
}
|
})
|
|
if (plot.$colors) {
|
let limit = chartColors.length
|
|
if (barcolors) {
|
_chart.color(`${_typefield}*${plot.Xaxis}`, (key, label) => {
|
if (barcolors[label]) {
|
return barcolors[label]
|
} else if (plot.$colors.has(key)) {
|
return plot.$colors.get(key)
|
} else {
|
colorIndex++
|
return chartColors[(colorIndex - 1) % limit]
|
}
|
})
|
} else {
|
_chart.color(`${_typefield}`, (key) => {
|
if (plot.$colors.has(key)) {
|
return plot.$colors.get(key)
|
} else {
|
colorIndex++
|
return chartColors[(colorIndex - 1) % limit]
|
}
|
})
|
}
|
} else {
|
_chart.color(_typefield)
|
}
|
if (plot.label !== 'false') {
|
_chart.label(`${_valfield}*${_typefield}`, (value, key) => {
|
if (plot.labelValue === 'zero' && value === 0) {
|
return null
|
}
|
|
if (plot.show === 'percent') {
|
value = value + '%'
|
}
|
|
if (plot.label === 'true' && plot.labelColor === 'custom' && plot.$colors && plot.$colors.has(key)) {
|
lablecfg.style.fill = plot.$colors.get(key)
|
}
|
|
return {
|
content: value,
|
...lablecfg
|
}
|
})
|
}
|
|
if (plot.barSize || plot.correction) {
|
_chart.size(plot.barSize || 35)
|
}
|
if (plot.selectColor) {
|
_chart.state({
|
selected: {
|
style: {
|
fill: plot.selectColor,
|
}
|
}
|
})
|
}
|
if (plot.barRadius) {
|
_chart.style({ radius: [plot.barRadius, plot.barRadius, 0, 0] })
|
}
|
} else if (plot.adjust === 'stack') {
|
let _chart = chart
|
.interval()
|
.position(`${plot.Xaxis}*${_valfield}`)
|
.adjust('stack')
|
.shape(plot.shape || 'rect')
|
.tooltip(`${plot.Xaxis}*${_valfield}*${_typefield}`, (name, value, type) => {
|
return {
|
name: type,
|
value: plot.show === 'percent' ? value + '%' : value
|
}
|
})
|
|
if (plot.$colors) {
|
let limit = chartColors.length
|
if (barcolors) {
|
_chart.color(`${_typefield}*${plot.Xaxis}`, (key, label) => {
|
if (barcolors[label]) {
|
return barcolors[label]
|
} else if (plot.$colors.has(key)) {
|
return plot.$colors.get(key)
|
} else {
|
colorIndex++
|
return chartColors[(colorIndex - 1) % limit]
|
}
|
})
|
} else {
|
_chart.color(`${_typefield}`, (key) => {
|
if (plot.$colors.has(key)) {
|
return plot.$colors.get(key)
|
} else {
|
colorIndex++
|
return chartColors[(colorIndex - 1) % limit]
|
}
|
})
|
}
|
} else {
|
_chart.color(_typefield)
|
}
|
if (plot.label !== 'false') {
|
_chart.label(`${_valfield}*${_typefield}`, (value, key) => {
|
if (plot.labelValue === 'zero' && value === 0) {
|
return null
|
}
|
|
if (plot.show === 'percent') {
|
value = value + '%'
|
}
|
|
if (plot.label === 'true' && plot.labelColor === 'custom' && plot.$colors && plot.$colors.has(key)) {
|
lablecfg.style.fill = plot.$colors.get(key)
|
}
|
|
return {
|
content: value,
|
...lablecfg
|
}
|
})
|
}
|
|
if (plot.barSize || plot.correction) {
|
_chart.size(plot.barSize || 35)
|
}
|
if (plot.selectColor) {
|
_chart.state({
|
selected: {
|
style: {
|
fill: plot.selectColor,
|
}
|
}
|
})
|
}
|
if (plot.barRadius) {
|
_chart.style({ radius: [plot.barRadius, plot.barRadius, 0, 0] })
|
}
|
}
|
|
chart.on('element:click', (ev) => {
|
let data = ev.data.data
|
|
if (plot.click === 'menus') {
|
let menu = null
|
|
if (plot.menus && plot.menus.length > 0) {
|
let s = data[plot.menuType] + ''
|
plot.menus.forEach(m => {
|
if (s !== m.sign) return
|
menu = m
|
})
|
}
|
if (!menu || !menu.MenuID) return
|
|
let newtab = {
|
MenuID: menu.MenuID,
|
MenuName: menu.MenuName,
|
MenuNo: menu.MenuNo || '',
|
type: menu.tabType,
|
param: {}
|
}
|
|
if (plot.joint === 'true') {
|
newtab.param.$BID = data.$$uuid || ''
|
|
Object.keys(data).forEach(key => {
|
if (/^\$/.test(key)) return
|
newtab.param[key] = data[key]
|
})
|
}
|
|
MKEmitter.emit('modifyTabs', newtab, true)
|
} else if (plot.click === 'menu') {
|
let menuId = plot.menu.slice(-1)[0]
|
let newtab = window.GLOB.mkThdMenus.filter(m => m.MenuID === menuId)[0]
|
|
if (!newtab && plot.MenuID) {
|
newtab = {
|
MenuID: plot.MenuID,
|
MenuName: plot.MenuName,
|
MenuNo: plot.MenuNo,
|
type: plot.tabType
|
}
|
} else if (!newtab) {
|
return
|
}
|
|
newtab = {
|
...newtab,
|
param: {}
|
}
|
|
if (plot.joint === 'true') {
|
newtab.param.$BID = data.$$uuid || ''
|
|
Object.keys(data).forEach(key => {
|
if (/^\$/.test(key)) return
|
newtab.param[key] = data[key]
|
})
|
}
|
|
MKEmitter.emit('modifyTabs', newtab, true)
|
} else {
|
MKEmitter.emit('resetSelectLine', config.uuid, (data ? data.$$uuid : ''), data)
|
}
|
})
|
|
if (plot.interaction && plot.interaction.length) {
|
plot.interaction.forEach(t => {
|
chart.interaction(t)
|
})
|
}
|
|
chart.render()
|
|
this.setState({chart})
|
}
|
|
refreshSearch = (list) => {
|
this.setState({search: list}, () => {
|
this.loadData()
|
})
|
}
|
|
downloadImage = () => {
|
const { chart, config } = this.state
|
const link = document.createElement('a');
|
const filename = `${config.name}${moment().format('YYYY-MM-DD HH_mm_ss')}.png`;
|
const canvas = chart.getCanvas();
|
canvas.get('timeline').stopAllAnimations();
|
|
setTimeout(() => {
|
const canvas = chart.getCanvas();
|
const canvasDom = canvas.get('el');
|
const dataURL = canvasDom.toDataURL('image/png');
|
|
if (window.Blob && window.URL) {
|
const arr = dataURL.split(',');
|
const mime = arr[0].match(/:(.*?);/)[1];
|
const bstr = atob(arr[1]);
|
let n = bstr.length;
|
const u8arr = new Uint8Array(n);
|
while (n--) {
|
u8arr[n] = bstr.charCodeAt(n);
|
}
|
const blobObj = new Blob([u8arr], { type: mime });
|
if (window.navigator.msSaveBlob) {
|
window.navigator.msSaveBlob(blobObj, filename);
|
} else {
|
link.addEventListener('click', () => {
|
link.download = filename;
|
link.href = window.URL.createObjectURL(blobObj);
|
});
|
}
|
}
|
const e = document.createEvent('MouseEvents');
|
e.initEvent('click', false, false);
|
link.dispatchEvent(e);
|
}, 16);
|
}
|
|
render() {
|
const { config, loading, empty, BID } = this.state
|
|
let style = {...config.style}
|
if (empty && config.plot.empty === 'hidden') {
|
style.opacity = 0
|
style.position = 'absolute'
|
style.zIndex = -1
|
style.width = '100%'
|
}
|
|
return (
|
<div className="custom-line-chart-plot-box" id={'anchor' + config.uuid} style={style}>
|
{loading ?
|
<div className="loading-mask">
|
<div className="ant-spin-blur"></div>
|
<Spin />
|
</div> : null
|
}
|
<NormalHeader config={config} BID={BID} refresh={this.refreshSearch} />
|
<div className="canvas-wrap">
|
{config.plot.download === 'enable' && this.state.chart && !empty ? <DownloadOutlined onClick={this.downloadImage} className="system-color download"/> : null}
|
<div className={'chart-action' + (config.plot.download === 'enable' ? ' downable' : '')}>
|
{config.action.map(item => {
|
if (item.OpenType === 'excelOut') {
|
return (
|
<ExcelOutButton
|
key={item.uuid}
|
BID={BID}
|
btn={item}
|
show="icon"
|
setting={config.setting}
|
/>
|
)
|
} else {
|
return (
|
<ExcelInButton
|
key={item.uuid}
|
BID={BID}
|
btn={item}
|
show="icon"
|
setting={config.setting}
|
/>
|
)
|
}
|
})}
|
</div>
|
<div className={'canvas' + (empty ? ' empty' : '')} id={this.state.chartId}></div>
|
</div>
|
{empty ? <Empty description={false}/> : null}
|
</div>
|
)
|
}
|
}
|
|
export default LineChart
|