king
2021-07-28 137fb8ea6af2789b3238b22bac31d80bced41dfe
src/menu/components/chart/antv-pie/index.jsx
@@ -1,14 +1,14 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Icon, Popover, notification } from 'antd'
import { Icon, Popover } from 'antd'
import { Chart } from '@antv/g2'
import DataSet from '@antv/data-set'
import DataSet, { DataView } from '@antv/data-set'
import MKEmitter from '@/utils/events.js'
import asyncComponent from '@/utils/asyncComponent'
import asyncIconComponent from '@/utils/asyncIconComponent'
import { resetStyle } from '@/utils/utils-custom.js'
import Utils from '@/utils/utils.js'
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
@@ -18,7 +18,6 @@
const ChartCompileForm = asyncIconComponent(() => import('./chartcompile'))
const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
const PasteComponent = asyncIconComponent(() => import('@/menu/components/share/pastecomponent'))
const LogComponent = asyncIconComponent(() => import('@/menu/components/share/logcomponent'))
const NormalHeader = asyncComponent(() => import('@/menu/components/share/normalheader'))
const UserComponent = asyncIconComponent(() => import('@/menu/components/share/usercomponent'))
const ClockComponent = asyncIconComponent(() => import('@/menu/components/share/clockcomponent'))
@@ -33,11 +32,12 @@
  state = {
    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    card: null,
    ismob: sessionStorage.getItem('appType') === 'mob',
    eventListener: null
  }
  UNSAFE_componentWillMount () {
    const { card } = this.props
    const { card, ismob } = this.props
    if (card.isNew) {
      let _plot = {
@@ -48,8 +48,15 @@
        name: card.name
      }
      if (ismob) {
        _plot.width = 24
      }
      if (card.subtype === 'ring') {
        _plot.innerRadius = 50
      } else if (card.subtype === 'nest') {
        _plot.innerRadius = 30
        _plot.radius = 80
      }
      let _card = {
@@ -105,9 +112,12 @@
  }
  componentDidMount () {
    this.pierender()
    MKEmitter.addListener('tabsChange', this.handleTabsChange)
    MKEmitter.addListener('submitStyle', this.getStyle)
    setTimeout(() => {
      this.viewrender()
    }, 1000)
  }
  shouldComponentUpdate (nextProps, nextState) {
@@ -134,7 +144,18 @@
        _element.innerHTML = ''
      }
      setTimeout(this.pierender, 100)
      this.$timer && clearTimeout(this.$timer)
      this.$timer = setTimeout(this.viewrender, 100)
    }
  }
  viewrender = () => {
    const { card } = this.state
    if (card.plot.shape === 'nest') {
      this.nestrender()
    } else {
      this.pierender()
    }
  }
@@ -145,13 +166,6 @@
      { label: '2003', value: 33.7 },
      { label: '2004', value: 30.7 },
      { label: '2005', value: 25.8 },
      { label: '2006', value: 31.7 },
      { label: '2007', value: 33 },
      { label: '2008', value: 46 },
      { label: '2009', value: 38.3 },
      { label: '2010', value: 28 },
      { label: '2011', value: 42.5 },
      { label: '2012', value: 30.3 }
    ]
    let data = xdata.map(item => {
@@ -164,13 +178,252 @@
    return data
  }
  pierender = () => {
    const { card } = this.state
    let plot = {...card.plot, height: card.plot.height - 80}
    let color = plot.color || 'rgba(0, 0, 0, 0.85)'
  getnestdata = (X_axis, Y_axis, type) => {
    const xdata = [
      { name: '狮子', type: '火象', value: 11 },
      { name: '白羊', type: '火象', value: 10 },
      { name: '水瓶', type: '风向', value: 14 },
      { name: '射手', type: '火象', value: 10 },
      { name: '双子', type: '风向', value: 7 },
      { name: '天平', type: '风向', value: 7 },
      { name: '摩羯', type: '土象', value: 14 },
      { name: '金牛', type: '土象', value: 3 },
      { name: '处女', type: '土象', value: 3 },
      { name: '天蝎', type: '水象', value: 11 },
      { name: '巨蟹', type: '水象', value: 5 },
      { name: '双鱼', type: '水象', value: 5 },
    ]
    let map = new Map()
    let sort = 1
    let data = xdata.map(item => {
      let _sort = sort
      if (map.has(item.type)) {
        _sort = map.get(item.type)
      } else {
        map.set(item.type, _sort)
        sort++
      }
      return {
        [X_axis]: item.name,
        [Y_axis]: item.value,
        [type]: item.type,
        $sort: _sort
      }
    })
    return data
  }
  nestrender = () => {
    const { card } = this.state
    const plot = card.plot
    let color = plot.color || 'rgba(0, 0, 0, 0.85)'
    let X_axis = plot.Xaxis || 'x'
    let Y_axis = plot.Yaxis || 'y'
    let type = plot.type || 'type'
    let height = plot.height || 400
    if (card.plot.title || card.search.length > 0) {
      height = height - 45
    }
    const _data = this.getnestdata(X_axis, Y_axis, type)
    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: card.uuid + 'canvas',
      autoFit: true,
      height: height,
      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,
    })
    if (plot.tooltip !== 'true') {
      chart.tooltip(false)
    } else {
      chart.tooltip({
        showTitle: false,
        showMarkers: false
      })
    }
    chart.legend(false)
    let chart1 = chart
      .interval()
      .adjust('stack')
      .position(Y_axis)
      .color(type)
      .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.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)
      .color(X_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.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()
  }
  pierender = () => {
    const { card } = this.state
    const plot = card.plot
    let color = plot.color || 'rgba(0, 0, 0, 0.85)'
    let X_axis = plot.Xaxis || 'x'
    let Y_axis = plot.Yaxis || 'y'
    let height = plot.height || 400
    if (card.plot.title || card.search.length > 0) {
      height = height - 45
    }
    let data = this.getdata(X_axis, Y_axis)
@@ -180,7 +433,7 @@
    const chart = new Chart({
      container: card.uuid + 'canvas',
      autoFit: true,
      height: plot.height || 400
      height: height
    })
    if (plot.shape !== 'nightingale' && plot.show !== 'value') {
@@ -245,6 +498,7 @@
      })
    }
    // 饼图或环图
    if (plot.shape !== 'nightingale') {
      let _chart = chart
        .interval()
@@ -260,24 +514,26 @@
            value: value
          }
        })
      if (plot.splitLine) {
        _chart.style({
          lineWidth: plot.splitLine,
          stroke: plot.splitColor,
        })
      }
      if (plot.label !== 'false') {
        if (plot.label === 'inner') {
          _chart.label(Y_axis, {
            offset: -30,
            content: (data) => {
              let _label = ''
              let _val = ''
              if (plot.show !== 'value') {
                _val = `${(data[Y_axis] * 100).toFixed(2)}%`
              } else {
                _val = `${data[Y_axis]}`
              }
              if (plot.label === 'inner') {
                _label = _val
              } else {
                _label = `${data[X_axis]}: ${_val}`
              }
              return _label
              return _val
            },
            style: {
              textAlign: 'center',
@@ -289,22 +545,17 @@
          })
        } else {
          _chart.label(Y_axis, {
            layout: { type: 'pie-spider' },
            layout: { type: plot.label === 'outer' ? 'pie-spider' : 'fixed-overlap' },
            labelHeight: 20,
            content: (data) => {
              let _label = ''
              let _val = ''
              if (plot.show !== 'value') {
                _val = `${(data[Y_axis] * 100).toFixed(2)}%`
              } else {
                _val = `${data[Y_axis]}`
              }
              if (plot.label === 'inner') {
                _label = _val
              } else {
                _label = `${data[X_axis]}: ${_val}`
              }
              return _label
              return `${data[X_axis]}: ${_val}`
            },
            labelLine: {
              style: {
@@ -317,10 +568,8 @@
          })
        }
      }
      chart.interaction('element-active')
    } else {
      chart.axis(false)
      chart.interaction('element-highlight')
      let _chart = chart
        .interval()
        .position(`${X_axis}*${Y_axis}`)
@@ -337,11 +586,19 @@
          }
          _chart.label(X_axis, _label)
          .style({
            lineWidth: 1,
            stroke: '#fff',
        }
        if (plot.splitLine) {
          _chart.style({
            lineWidth: plot.splitLine,
            stroke: plot.splitColor,
          })
        }
    }
    if (plot.interaction && plot.interaction.length) {
      plot.interaction.forEach(t => {
        chart.interaction(t)
      })
    }
    chart.render()
@@ -349,13 +606,16 @@
  updateComponent = (component) => {
    const card = fromJS(this.state.card).toJS()
    let refresh = false
    if (!is(fromJS(component.plot), fromJS(card.plot)) || !is(fromJS(component.style), fromJS(card.style))) {
      let _element = document.getElementById(card.uuid + 'canvas')
      if (_element) {
        _element.innerHTML = ''
      }
      refresh = true
      this.$timer && clearTimeout(this.$timer)
      this.$timer = setTimeout(() => {
        this.viewrender()
      }, 150)
    }
    component.width = component.plot.width
@@ -363,12 +623,6 @@
    
    this.setState({
      card: component
    }, () => {
      if (refresh) {
        setTimeout(() => {
          this.pierender()
        }, 100)
      }
    })
    this.props.updateConfig(component)
  }
@@ -410,32 +664,6 @@
    this.updateComponent(_card)
  }
  handleLog = (type, logs, item) => {
    let card = fromJS(this.state.card).toJS()
    if (type === 'revert') {
      card.action = card.action ? [...card.action, item] : [item]
      card.btnlog = logs
      this.setState({ card })
      this.props.updateConfig(card)
      notification.success({
        top: 92,
        message: '恢复成功!',
        duration: 2
      })
    } else {
      card.btnlog = logs
      this.setState({ card })
      this.props.updateConfig(card)
      notification.success({
        top: 92,
        message: '清除成功!',
        duration: 2
      })
    }
  }
  clickComponent = (e) => {
    if (sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'component') {
      e.stopPropagation()
@@ -444,19 +672,18 @@
  }
  render() {
    const { card } = this.state
    const { card, ismob } = this.state
    let _style = resetStyle(card.style)
    return (
      <div className="menu-pie-chart-edit-box" style={{...card.style, height: card.plot.height || 400}} onClick={this.clickComponent} id={card.uuid}>
        <NormalHeader config={card} updateComponent={this.updateComponent}/>
      <div className="menu-pie-chart-edit-box" style={{..._style, height: card.plot.height || 400}} onClick={this.clickComponent} id={card.uuid}>
        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
          <div className="mk-popover-control">
            <Icon className="plus" title="添加搜索" onClick={this.addSearch} type="plus-circle" />
            {!ismob ? <Icon className="plus" title="添加搜索" onClick={this.addSearch} type="plus-circle" /> : null}
            <ChartCompileForm config={card} dict={this.state.dict} plotchange={this.updateComponent}/>
            <CopyComponent type="pie" card={card}/>
            <PasteComponent config={card} options={['search', 'form']} updateConfig={this.updateComponent} />
            <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" />
            <LogComponent btnlog={card.btnlog || []} handlelog={this.handleLog} />
            <ClockComponent config={card} updateConfig={this.updateComponent}/>
            <UserComponent config={card}/>
            <Icon className="close" title="delete" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
@@ -465,6 +692,7 @@
        } trigger="hover">
          <Icon type="tool" />
        </Popover>
        {card.plot.title || card.search.length > 0 ? <NormalHeader config={card} updateComponent={this.updateComponent}/> : null}
        <div className="canvas" id={card.uuid + 'canvas'}></div>
      </div>
    )