From 31ec63f0419895876cbaba99637a884a32d33d0d Mon Sep 17 00:00:00 2001 From: king <18310653075@163.com> Date: 星期三, 01 九月 2021 10:31:45 +0800 Subject: [PATCH] 2021-09-01 --- src/tabviews/custom/components/chart/antv-pie/index.jsx | 675 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 files changed, 574 insertions(+), 101 deletions(-) diff --git a/src/tabviews/custom/components/chart/antv-pie/index.jsx b/src/tabviews/custom/components/chart/antv-pie/index.jsx index dd7fa3f..1132d75 100644 --- a/src/tabviews/custom/components/chart/antv-pie/index.jsx +++ b/src/tabviews/custom/components/chart/antv-pie/index.jsx @@ -3,16 +3,21 @@ import { is, fromJS } from 'immutable' import { Chart } from '@antv/g2' import { connect } from 'react-redux' -import DataSet from '@antv/data-set' +import DataSet, { DataView } from '@antv/data-set' import { Spin, Empty, notification } from 'antd' +import moment from 'moment' -// import searchLine from '../../share/searchLine' import Api from '@/api' import Utils from '@/utils/utils.js' import { modifyTabview } from '@/store/action' import { chartColors } from '@/utils/option.js' +// import asyncComponent from '@/utils/asyncComponent' import UtilsDM from '@/utils/utils-datamanage.js' +import MKEmitter from '@/utils/events.js' +import NormalHeader from '@/tabviews/custom/components/share/normalheader' import './index.scss' + +// const NormalHeader = asyncComponent(() => import('@/tabviews/custom/components/share/normalheader')) class PieChart extends Component { static propTpyes = { @@ -21,10 +26,10 @@ config: PropTypes.object, // 缁勪欢閰嶇疆淇℃伅 mainSearch: PropTypes.any, // 澶栧眰鎼滅储鏉′欢 menuType: PropTypes.any, // 鑿滃崟绫诲瀷 - dataManager: PropTypes.any, // 鏁版嵁鏉冮檺 } state = { + BID: '', // 涓婄骇ID config: null, // 鍥捐〃閰嶇疆淇℃伅 empty: true, // 鍥捐〃鏁版嵁涓虹┖ loading: false, // 鏁版嵁鍔犺浇鐘舵�� @@ -34,11 +39,10 @@ plot: null, // 鍥捐〃璁剧疆 data: null, // 鏁版嵁 search: null, // 鎼滅储鏉′欢 - showHeader: false // 瀛樺湪鏍囬銆佹悳绱€�佹垨缁熻鏁版嵁鏃舵樉绀� } UNSAFE_componentWillMount () { - const { config, data, initdata } = this.props + const { config, data, initdata, BID } = this.props let _config = fromJS(config).toJS() let _data = null @@ -52,29 +56,26 @@ _sync = false } - let showHeader = false - if (config.plot.title || config.search.length > 0) { - showHeader = true - _config.plot.height = _config.plot.height - 80 - } else { - _config.plot.height = _config.plot.height - 30 - } + _config.style.height = config.plot.height || 400 - if (_config.style) { - _config.style = {..._config.style, minHeight: (config.plot.height || 400)} - } else { - _config.style = {minHeight: (config.plot.height || 400)} - } + let decimal = 0 + _config.columns.forEach(col => { + if (_config.plot.Yaxis === col.field && /Decimal/ig.test(col.datatype)) { + decimal = +col.datatype.replace(/^Decimal\(18,/ig, '').replace(/\)/ig, '') + } + }) + + _config.plot.$decimal = decimal this.setState({ config: _config, data: _data, + BID: BID || '', arr_field: _config.columns.map(col => col.field).join(','), plot: _config.plot, sync: _sync, title: config.plot.title, - search: Utils.initMainSearch(config.search), - showHeader + search: Utils.initMainSearch(config.search) }, () => { if (config.setting.sync !== 'true' && config.setting.onload === 'true') { this.loadData() @@ -82,13 +83,6 @@ this.handleData() } }) - } - - /** - * @description 鏍¢獙鍥捐〃鐨勬寜閽粍锛屽鏋滀负缁熻鍥捐〃锛岃绠楀浘琛ㄥ瓧娈� - */ - componentDidMount () { - } /** @@ -106,12 +100,10 @@ this.setState({sync: false, data: _data}, () => { this.handleData() }) - } else if (!is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) { - if (config.setting.syncRefresh === 'true') { - this.setState({}, () => { - this.loadData() - }) - } + } else if (config.setting.syncRefresh && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) { + this.setState({}, () => { + this.loadData() + }) } } @@ -119,20 +111,123 @@ return !is(fromJS(this.state), fromJS(nextState)) } + componentDidMount () { + MKEmitter.addListener('reloadData', this.reloadData) + MKEmitter.addListener('resetSelectLine', this.resetParentParam) + this.handleTimer() + } + + /** + * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆 + */ + componentWillUnmount () { + clearTimeout(this.timer) + this.setState = () => { + return + } + MKEmitter.removeListener('reloadData', this.reloadData) + MKEmitter.removeListener('resetSelectLine', this.resetParentParam) + } + + handleTimer = () => { + const { config } = this.state + + if (!config.timer) return + + const _change = { '15s': 15000, '30s': 30000, '1min': 60000, '5min': 300000, '10min': 600000, '15min': 900000, '30min': 1800000, '1hour': 3600000 } + + let timer = _change[config.timer] + + if (!timer) return + + let _param = { + func: 's_get_timers_role', + LText: `select '${window.GLOB.appkey || ''}','${config.uuid}'`, + timer_type: config.timer, + component_id: config.uuid + } + + _param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') // 鏃堕棿鎴� + _param.LText = Utils.formatOptions(_param.LText) // 鍏抽敭瀛楃鏇挎崲锛宐ase64鍔犲瘑 + _param.secretkey = Utils.encrypt(_param.LText, _param.timestamp) // md5瀵嗛挜 + + Api.getSystemConfig(_param).then(result => { + if (!result.status) { + notification.warning({ + top: 92, + message: result.message, + duration: 5 + }) + return + } else if (result.run_type) { + this.setState({timer}) + this.timer = setTimeout(() => { + this.timerTask() + }, timer) + } + }) + } + + timerTask = () => { + const { timer } = this.state + if (!timer) return + + this.loadData(true) + + this.timer = setTimeout(() => { + this.timerTask() + }, timer) + } + + 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) { + this.setState({ BID: id }, () => { + this.loadData() + }) + } + } + handleData = () => { - let _element = document.getElementById(this.state.chartId) + const { plot, chartId } = this.state + + let _element = document.getElementById(chartId) if (_element) { _element.innerHTML = '' } - this.pierender() + + if (plot.shape === 'nest') { + this.nestrender() + } else { + this.pierender() + } } - async loadData () { - const { mainSearch, BID, menuType, dataManager } = this.props - const { config, arr_field, search } = this.state + async loadData (hastimer) { + const { mainSearch, menuType } = this.props + const { config, arr_field, search, BID } = this.state + + if (config.setting.supModule && !BID) { // BID 涓嶅瓨鍦ㄦ椂锛屼笉鍋氭煡璇� + this.setState({ + data: [] + }, () => { + this.handleData() + }) + return + } let searches = fromJS(search).toJS() - if (mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢 + if (config.setting.useMSearch && mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢 let keys = searches.map(item => item.key) mainSearch.forEach(item => { if (!keys.includes(item.key)) { @@ -141,12 +236,19 @@ }) } - this.setState({ - loading: true - }) + 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, menuType, dataManager) + let param = UtilsDM.getQueryDataParams(config.setting, arr_field, searches, _orderBy, '', '', BID, menuType) let result = await Api.genericInterface(param) if (result.status) { @@ -158,7 +260,8 @@ }) } else { this.setState({ - loading: false + loading: false, + timer: null }) notification.error({ top: 92, @@ -175,19 +278,12 @@ * 3銆佹煴鐘跺浘鏁版嵁琛ラ綈 */ getdata = () => { - const { data, plot, config } = this.state + const { data, plot } = this.state if (!data) { this.setState({empty: true}) return [] } - - let decimal = 0 - config.columns.forEach(col => { - if (plot.Yaxis === col.field && /Decimal/ig.test(col.datatype)) { - decimal = +col.datatype.replace(/^Decimal\(18,/ig, '').replace(/\)/ig, '') - } - }) let _data = [] let _cdata = fromJS(data).toJS() @@ -198,14 +294,16 @@ if (typeof(item[plot.Yaxis]) !== 'number') { item[plot.Yaxis] = parseFloat(item[plot.Yaxis]) if (isNaN(item[plot.Yaxis])) { - item[plot.Yaxis] = 0 + return } + } else if (!item[plot.Xaxis]) { + return } - if (item[plot.Xaxis] && !_mdata.has(item[plot.Xaxis])) { + if (!_mdata.has(item[plot.Xaxis])) { item.$count = 1 _mdata.set(item[plot.Xaxis], item) - } else if (item[plot.Xaxis]) { + } else { let _item = _mdata.get(item[plot.Xaxis]) _item.$count++ _item[plot.Yaxis] += item[plot.Yaxis] @@ -216,8 +314,7 @@ _data = [..._mdata.values()] _data = _data.map(item => { item[plot.Yaxis] = item[plot.Yaxis] / item.$count - item[plot.Yaxis] = item[plot.Yaxis].toFixed(decimal) - item[plot.Yaxis] = +item[plot.Yaxis] + item[plot.Yaxis] = +item[plot.Yaxis].toFixed(plot.$decimal) return item }) @@ -227,13 +324,15 @@ if (typeof(item[plot.Yaxis]) !== 'number') { item[plot.Yaxis] = parseFloat(item[plot.Yaxis]) if (isNaN(item[plot.Yaxis])) { - item[plot.Yaxis] = 0 + return } + } else if (!item[plot.Xaxis]) { + return } - if (item[plot.Xaxis] && !_mdata.has(item[plot.Xaxis])) { + if (!_mdata.has(item[plot.Xaxis])) { _mdata.set(item[plot.Xaxis], item) - } else if (item[plot.Xaxis]) { + } else { let _item = _mdata.get(item[plot.Xaxis]) _item[plot.Yaxis] += item[plot.Yaxis] _mdata.set(item[plot.Xaxis], _item) @@ -242,34 +341,390 @@ _data = [..._mdata.values()] _data = _data.map(item => { - item[plot.Yaxis] = item[plot.Yaxis].toFixed(decimal) - item[plot.Yaxis] = +item[plot.Yaxis] + item[plot.Yaxis] = +item[plot.Yaxis].toFixed(plot.$decimal) return item }) } else { // plot.repeat === 'unrepeat' let _mdata = new Map() _cdata.forEach(item => { - if (item[plot.Xaxis] && !_mdata.has(item[plot.Xaxis])) { - - if (typeof(item[plot.Yaxis]) !== 'number') { - item[plot.Yaxis] = parseFloat(item[plot.Yaxis]) - if (isNaN(item[plot.Yaxis])) { - item[plot.Yaxis] = 0 - } - } - - item[plot.Yaxis] = item[plot.Yaxis].toFixed(decimal) - item[plot.Yaxis] = +item[plot.Yaxis] - - _mdata.set(item[plot.Xaxis], item) + if (!item[plot.Xaxis] || _mdata.has(item[plot.Xaxis])) { + return } + if (typeof(item[plot.Yaxis]) !== 'number') { + item[plot.Yaxis] = parseFloat(item[plot.Yaxis]) + if (isNaN(item[plot.Yaxis])) { + return + } + } + + item[plot.Yaxis] = +item[plot.Yaxis].toFixed(plot.$decimal) + + _mdata.set(item[plot.Xaxis], item) }) _data = [..._mdata.values()] } this.setState({empty: _data.length === 0}) + return _data + } + + getnestdata = () => { + const { data, plot } = this.state + + if (!data) { + this.setState({empty: true}) + return [] + } + + let _data = [] + let _cdata = fromJS(data).toJS() + + if (plot.repeat === 'average') { + let _mdata = new Map() + let map = new Map() + let sort = 1 + _cdata.forEach(item => { + if (typeof(item[plot.Yaxis]) !== 'number') { + item[plot.Yaxis] = parseFloat(item[plot.Yaxis]) + if (isNaN(item[plot.Yaxis])) { + return + } + } else if (!item[plot.Xaxis] || !item[plot.type]) { + return + } + + let sign = item[plot.type] + item[plot.Xaxis] + + if (!_mdata.has(sign)) { + let _sort = sort + if (map.has(item.type)) { + _sort = map.get(item.type) + } else { + map.set(item.type, _sort) + sort++ + } + + item.$count = 1 + item.$sort = _sort + _mdata.set(sign, item) + } else { + let _item = _mdata.get(sign) + _item.$count++ + _item[plot.Yaxis] += item[plot.Yaxis] + _mdata.set(sign, _item) + } + }) + + _data = [..._mdata.values()] + _data = _data.map(item => { + item[plot.Yaxis] = item[plot.Yaxis] / item.$count + item[plot.Yaxis] = +item[plot.Yaxis].toFixed(plot.$decimal) + + return item + }) + } else if (plot.repeat === 'cumsum') { + let _mdata = new Map() + let map = new Map() + let sort = 1 + _cdata.forEach(item => { + if (typeof(item[plot.Yaxis]) !== 'number') { + item[plot.Yaxis] = parseFloat(item[plot.Yaxis]) + if (isNaN(item[plot.Yaxis])) { + return + } + } else if (!item[plot.Xaxis] || !item[plot.type]) { + return + } + + let sign = item[plot.type] + item[plot.Xaxis] + + if (!_mdata.has(sign)) { + let _sort = sort + if (map.has(item.type)) { + _sort = map.get(item.type) + } else { + map.set(item.type, _sort) + sort++ + } + + item.$sort = _sort + _mdata.set(sign, item) + } else { + let _item = _mdata.get(sign) + _item[plot.Yaxis] += item[plot.Yaxis] + _mdata.set(sign, _item) + } + }) + + _data = [..._mdata.values()] + _data = _data.map(item => { + item[plot.Yaxis] = +item[plot.Yaxis].toFixed(plot.$decimal) + return item + }) + } else { // plot.repeat === 'unrepeat' + let _mdata = new Map() + let map = new Map() + let sort = 1 + _cdata.forEach(item => { + let sign = item[plot.type] + item[plot.Xaxis] + if (!item[plot.Xaxis] || !item[plot.type] || _mdata.has(sign)) { + return + } + + if (typeof(item[plot.Yaxis]) !== 'number') { + item[plot.Yaxis] = parseFloat(item[plot.Yaxis]) + if (isNaN(item[plot.Yaxis])) { + return + } + } + + let _sort = sort + if (map.has(item.type)) { + _sort = map.get(item.type) + } else { + map.set(item.type, _sort) + sort++ + } + + item.$sort = _sort + item[plot.Yaxis] = +item[plot.Yaxis].toFixed(plot.$decimal) + + _mdata.set(sign, item) + }) + + _data = [..._mdata.values()] + } + + this.setState({empty: _data.length === 0}) + + return _data + } + + nestrender = () => { + const { plot, chartId } = this.state + + let X_axis = plot.Xaxis + let Y_axis = plot.Yaxis + let type = plot.type + let color = plot.color + + let colors = new Map() + let colorIndex = 0 + + if (plot.colors && plot.colors.length > 0) { + plot.colors.forEach(item => { + if (!colors.has(item.label)) { + colors.set(item.label, item.color) + } + }) + } + + let _data = this.getnestdata() + + const dvx = new DataView().source(_data) + + dvx.transform({ + type: 'sort-by', + fields: ['$sort'] + }) + + let data = dvx.rows + + // 閫氳繃 DataSet 璁$畻鐧惧垎姣� + const dv = new DataView() + dv.source(data).transform({ + type: 'percent', + field: Y_axis, + dimension: type, + as: '$percent' + }) + + const dv1 = new DataView() + dv1.source(data).transform({ + type: 'percent', + field: Y_axis, + dimension: X_axis, + as: '$percent', + }) + + const chart = new Chart({ + container: chartId, + autoFit: true, + height: this.wrap.offsetHeight - 30, + padding: 0, + }) + + chart.data(dv.rows) + + if (plot.show !== 'value') { + chart.scale('percent', { + formatter: (val) => { + val = val * 100 + '%' + return val + } + }) + + Y_axis = '$percent' + } + let radius = plot.radius / 100 + let innerRadius = plot.innerRadius / 100 + + chart.coordinate('theta', { + innerRadius: innerRadius, + radius: innerRadius + (radius - innerRadius) / 2, + }) + chart.tooltip({ + showTitle: false, + showMarkers: false, + }) + chart.legend(false) + let chart1 = chart + .interval() + .adjust('stack') + .position(Y_axis) + .tooltip(`${type}*${Y_axis}`, (type, percent) => { + if (plot.show !== 'value') { + percent = (percent * 100).toFixed(2) + '%' + } + return { + name: type, + value: percent, + } + }) + if (plot.splitLine) { + chart1.style({ + lineWidth: plot.splitLine, + stroke: plot.splitColor, + }) + } + if (plot.colors && plot.colors.length > 0) { + let limit = chartColors.length + chart1.color(type, (_type) => { + if (colors.has(_type)) { + return colors.get(_type) + } else { + let _c = chartColors[colorIndex % limit] + colors.set(type, _c) + colorIndex++ + return _c + } + }) + } else { + chart1.color(type) + } + + if (plot.label !== 'false') { + chart1.label(type, { + offset: -10, + }) + } + + const outterView = chart.createView() + + outterView.data(dv1.rows) + + if (plot.show !== 'value') { + outterView.scale('percent', { + formatter: (val) => { + val = val * 100 + '%' + return val + } + }) + } + outterView.coordinate('theta', { + innerRadius: (innerRadius + (radius - innerRadius) / 2) / radius, + radius: radius + }) + let chart2 = outterView + .interval() + .adjust('stack') + .position(Y_axis) + .tooltip(`${X_axis}*${Y_axis}`, (name, value) => { + if (plot.show !== 'value') { + value = (value * 100).toFixed(2) + '%' + } + return { + name: name, + value: value + } + }) + + if (plot.splitLine) { + chart2.style({ + lineWidth: plot.splitLine, + stroke: plot.splitColor, + }) + } + if (plot.colors && plot.colors.length > 0) { + let limit = chartColors.length + chart2.color(X_axis, (type) => { + if (colors.has(type)) { + return colors.get(type) + } else { + let _c = chartColors[colorIndex % limit] + colors.set(type, _c) + colorIndex++ + return _c + } + }) + } else { + chart2.color(X_axis) + } + + if (plot.label !== 'false') { + if (plot.label === 'inner') { + chart2.label(Y_axis, { + offset: -30, + content: (data) => { + let _val = '' + if (plot.show !== 'value') { + _val = `${(data[Y_axis] * 100).toFixed(2)}%` + } else { + _val = `${data[Y_axis]}` + } + return _val + }, + style: { + textAlign: 'center', + fontSize: 16, + shadowBlur: 2, + shadowColor: 'rgba(0, 0, 0, .45)', + fill: '#fff', + } + }) + } else { + chart2.label(Y_axis, { + layout: { type: plot.label === 'outer' ? 'pie-spider' : 'fixed-overlap' }, + labelHeight: 20, + content: (data) => { + let _val = '' + if (plot.show !== 'value') { + _val = `${(data[Y_axis] * 100).toFixed(2)}%` + } else { + _val = `${data[Y_axis]}` + } + + return `${data[X_axis]}: ${_val}` + }, + labelLine: { + style: { + lineWidth: 0.5, + }, + }, + style: { + fill: color + } + }) + } + } + if (plot.interaction && plot.interaction.length) { + plot.interaction.forEach(t => { + chart.interaction(t) + }) + } + chart.render() } /** @@ -277,12 +732,13 @@ */ pierender = () => { const { plot, chartId } = this.state - let color = plot.color || 'rgba(0, 0, 0, 0.85)' - let X_axis = plot.Xaxis || 'x' - let Y_axis = plot.Yaxis || 'y' + let color = plot.color - let data = this.getdata(X_axis, Y_axis) + let X_axis = plot.Xaxis + let Y_axis = plot.Yaxis + + let data = this.getdata() const ds = new DataSet() const dv = ds.createView().source(data) @@ -290,7 +746,7 @@ const chart = new Chart({ container: chartId, autoFit: true, - height: plot.height || 400 + height: this.wrap.offsetHeight - 30 }) if (plot.shape !== 'nightingale' && plot.show !== 'value') { @@ -377,14 +833,23 @@ value: value } }) + + if (plot.splitLine) { + _chart.style({ + lineWidth: plot.splitLine, + stroke: plot.splitColor, + }) + } if (plot.colors && plot.colors.length > 0) { let limit = chartColors.length _chart.color(X_axis, (type) => { - if (colors.get(type)) { + if (colors.has(type)) { return colors.get(type) } else { - colors.set(type, chartColors[colorIndex % limit]) + let _c = chartColors[colorIndex % limit] + colors.set(type, _c) colorIndex++ + return _c } }) } else { @@ -413,7 +878,7 @@ }) } else { _chart.label(Y_axis, { - layout: { type: 'pie-spider' }, + layout: { type: plot.label === 'outer' ? 'pie-spider' : 'fixed-overlap' }, labelHeight: 20, content: (data) => { let _val = '' @@ -436,10 +901,8 @@ }) } } - chart.interaction('element-active') } else { chart.axis(false) - chart.interaction('element-highlight') let _chart = chart .interval() .position(`${X_axis}*${Y_axis}`) @@ -447,11 +910,13 @@ if (plot.colors && plot.colors.length > 0) { let limit = chartColors.length _chart.color(X_axis, (type) => { - if (colors.get(type)) { + if (colors.has(type)) { return colors.get(type) } else { - colors.set(type, chartColors[colorIndex % limit]) + let _c = chartColors[colorIndex % limit] + colors.set(type, _c) colorIndex++ + return _c } }) } else { @@ -468,15 +933,17 @@ } _chart.label(X_axis, _label) - .style({ - lineWidth: 1, - stroke: '#fff', + } + if (plot.splitLine) { + _chart.style({ + lineWidth: plot.splitLine, + stroke: plot.splitColor, }) } } if (plot.linkmenu && plot.linkmenu.length > 0) { - let menu_id = plot.linkmenu[plot.linkmenu.length - 1] + let menu_id = plot.linkmenu.slice(-1)[0] let menu = this.props.permMenus.filter(m => m.MenuID === menu_id)[0] || '' chart.on('element:dblclick', (ev) => { @@ -500,8 +967,7 @@ ...menu, selected: true, param: { - BID: primaryId, - data: data + $BID: primaryId } } @@ -510,7 +976,7 @@ return tab.MenuID !== newtab.MenuID }) - if (this.props.tabviews.length !== tabs.length) { + if (this.props.tabviews.length > tabs.length) { this.props.modifyTabview(fromJS(tabs).toJS()) } @@ -518,17 +984,27 @@ tabs.push(newtab) this.props.modifyTabview(tabs) }) - } catch { + } catch (e) { console.warn('鑿滃崟鎵撳紑澶辫触锛�') } }) } - + if (plot.interaction && plot.interaction.length) { + plot.interaction.forEach(t => { + chart.interaction(t) + }) + } chart.render() } + refreshSearch = (list) => { + this.setState({search: list}, () => { + this.loadData() + }) + } + render() { - const { showHeader, config, loading, title, empty } = this.state + const { config, loading, empty, BID } = this.state return ( <div className="custom-pie-chart-plot-box" style={config.style}> @@ -538,11 +1014,8 @@ <Spin /> </div> : null } - {showHeader ? <div className="chart-header" style={config.headerStyle}> - <span className="chart-title">{title}</span> - {/* <searchLine /> */} - </div> : null} - <div className="canvas-wrap"> + <NormalHeader config={config} BID={BID} menuType={this.props.menuType} refresh={this.refreshSearch} /> + <div className="canvas-wrap" ref={ref => this.wrap = ref}> <div className={'canvas' + (empty ? ' empty' : '')} id={this.state.chartId}></div> </div> {empty ? <Empty description={false}/> : null} -- Gitblit v1.8.0