supervons / react-native-echarts-pro

A React-Native charts based on Apache ECharts, support various charts and map.
https://supervons.github.io/react-native-echarts-pro-docs/
MIT License
216 stars 32 forks source link

使用setNewOption渲染图表有问题 #103

Closed yuepy closed 1 year ago

yuepy commented 1 year ago

版本: "react-native": "0.69.3", "react-native-echarts-pro": "1.9.0", "react-native-webview": "^12.0.2", "react": "18.1.0", 问题描述:静态数据option图表正常渲染,改为从父组件获取data,setNewoption更新option的方式时,不能正常渲染,option为自定义图表使用了包含 function 的renderItem,麻烦帮忙看一下 //子组件 import React,{useEffect,useRef} from 'react'; import { View, Dimensions, } from 'react-native'; import RNEChartsPro from "react-native-echarts-pro"; let E_HEIGHT = Dimensions.get('window').height; let E_WIDTH = Dimensions.get('window').width; const colors = ['#EE4560', '#F39253', '#F9C353', '#EBDB20', '#9FE049', '#4BD3AF', '#24B9E5', '#1690FF', '#3265FE', '#6F4FF4', '#823EE0', '#D268CB']; const SuperPie = ({data}) =>{ const pieRef = useRef() const [option, setOption] = useState(getOption()); const [formatterData,setFormatterData] = useState(getFormatter()); useEffect(()=>{ setFormatterData(getFormatter()) },[data]) useEffect(()=>{ //更新formatterData再去更新option if(data.length==0) return; setOption(getOption()) },[formatterData]) useEffect(()=>{ if(!pieRef.current) return; pieRef.current.setNewOption(option) },[option])

    //获取图表formatterVariable 
    function getFormatter(){
        let formatterVariable = {
            totalAngleValue:0,
            maxRadiusValue:0,
            colors:colors,
            angleAcc:formatterData?formatterData.angleAcc:[],
            data:data
        }
        for (const item of data) {
          const radiusValue = item['count'] || 0
          formatterVariable.totalAngleValue = formatterVariable.totalAngleValue + item['value']
          formatterVariable.maxRadiusValue = Math.max(radiusValue,formatterVariable.maxRadiusValue)
        }
        return formatterVariable;
    }
    function getOption(){
        if(data.length==0) return {}
        let customData = []
        let totalAngleValue = 0
        let maxRadiusValue = 0
        for (const item of data) {
          const radiusValue = item['count'] || 0
          customData.push([radiusValue, item['value']])
          totalAngleValue = totalAngleValue + item['value']
          maxRadiusValue = Math.max(radiusValue, maxRadiusValue)
        }
        const option = {
          tooltip: {
            trigger: 'item',
            confine: true,
            padding: 0,
            textStyle:{
                fontSize:8,
                color:'#F00'
            },
            backgroundColor: 'rgba(0,0,0,0)',
            borderColor: 'rgba(0,0,0,0)',
            shadowColor: 'rgba(0,0,0,0)',
            formatter:function(params){
                const { dataIndex } = params
                const tooltipData = formatterVariable.data[dataIndex]
                const { project } = tooltipData.extra
                // 交易金额需要折算为万元
                let projectContent = ''
                for (const item of project) {
                    const pCount = item.tradeCustomerCount
                    const pAmount = item.tradeCustomerAmount
                    projectContent += '<tr><td>'+item.projectName+'</td><td class="num">'+pCount+'</td><td class="num">'+pAmount+'</td></tr>'
                }
                const content = '<div class="g-tooltip"><div class="container"><table class="tooltip-table"><thead><tr><th></th><th>交易客户数</th><th>交易金额 (万元)</th></tr></thead><tbody><tr><td>'+tooltipData.name+'</td><td class="num">'+tooltipData.count+'</td><td class="num">'+tooltipData.value+'</td></tr>'+projectContent+'</tbody></table></div></div>'
                return content;
            }
          },
          polar: {
            center: ['40%', '50%'],
            //radius: [that.innerRadius, that.outerRadius]
            radius: ['25%', '90%']
          },
          // 相当于x轴
          radiusAxis: {
            show: false,
            type: 'value',
            slient: true,
            max: maxRadiusValue
          },
          // 相当于y轴
          angleAxis: {
            show: false,
            type: 'value',
            slient: true,
            max: totalAngleValue
          },
          series: [
            {
              name: 'innerCircle',
              type: 'pie',
              silent: true,
              center: ['40%', '50%'],
              radius: ['20%', '21.5%'],
              emptyCircleStyle: {
                color: data.length ? 'rgba(50, 101, 254, 0.2)' : 'rgba(50,101,254,0)'
              },
              data: []
            },
            {
              name: 'superPie',
              type: 'custom',
              coordinateSystem: 'polar',
              selectedMode: 'single',
              labelLayout: {
                align: 'center',
                verticalAlign: 'middle'
              },
              renderItem: function (params, api) {
                //let angleAcc = []
                const { dataIndex } = params
                const values = [api.value(0), api.value(1)]
                const coord = api.coord(values)
                const size = api.size([formatterVariable.maxRadiusValue, formatterVariable.totalAngleValue], values)
                const startAngle = dataIndex === 0 ? -Math.PI / 2 : formatterVariable.angleAcc[dataIndex - 1]
                const endAngle = startAngle + (api.value(1) / formatterVariable.totalAngleValue) * size[1]
                formatterVariable.angleAcc.push(endAngle)

                // 饼图内文字角度或半径占位过小的不显示
                let text = ''
                if (values[1]) {
                  const anglePercent = (api.value(1) / formatterVariable.totalAngleValue) * 100
                  const radiusPercent = (api.value(0) / formatterVariable.maxRadiusValue) * 100
                  text = anglePercent > 5 && radiusPercent > 30 ? anglePercent.toFixed(2)+'%' : ''
                }

                // 校准中心label偏移问题
                const targetSize = api.size(values)
                let labelX = targetSize[0] / 2 - 25
                if (endAngle - startAngle > endAngle) {
                  if (targetSize[1] > 4) {
                    labelX = targetSize[0] / 2 + params.coordSys.r0 / 2 + 10
                  } else if (targetSize[1] > 3.2) {
                    labelX = targetSize[0] / 2
                  } else if (targetSize[1] > 2) {
                    labelX = targetSize[0] / 2 - 10
                  }
                } else {
                  if (startAngle > 3) {
                    labelX = 0
                  } else {
                    labelX = -15
                  }
                }

                return {
                  type: 'sector',
                  shape: {
                    cx: params.coordSys.cx,
                    cy: params.coordSys.cy,
                    r0: params.coordSys.r0,
                    r: coord[2],
                    startAngle,
                    endAngle
                  },
                  style: {
                    fill: formatterVariable.colors[params.dataIndex]
                  },
                  textContent: {
                    type: 'text',
                    style: {
                      text,
                      fontSize: 8,
                      fill: '#fff',
                      textAlign: 'center',
                      x: labelX
                      // y: 70
                    }
                  },
                  textConfig: {
                    position: ['50%', '50%']
                  },
                  emphasis: {
                    style: {
                      lineWidth: 1,
                      stroke: 'rgba(255, 255, 255, 0.8)',
                      shadowColor: 'rgba(7,33,91,0.9)',
                      shadowBlur: 32
                    }
                  },
                  select: {
                    style: {
                      lineWidth: 1,
                      stroke: 'rgba(255, 255, 255, 0.8)',
                      shadowColor: 'rgba(7,33,91,0.9)',
                      shadowBlur: 32
                    }
                  }
                }
              },
              data: customData
            }
          ]
        }
        return option
    }
    return(
        <>
            <View style={{ height: 300 }}>
            <RNEChartsPro ref={pieRef} formatterVariable={formatterData} option={option} width={E_WIDTH/2} height={(E_HEIGHT-60)/7*3-40} enableParseStringFunction/>
            </View>
        </>
    )
}

const data1 = [{
    "name": "1",
    "value": 17395369036.76,
    "count": 6728,
    "extra": {
        "project": [{
            "tradeCustomerCount": 4138,
            "projectName": "2",
            "tradeCustomerAmount": "11848075449.20"
        }, {
            "tradeCustomerCount": 4399,
            "projectName": "3",
            "tradeCustomerAmount": "2412299322.40"
        }]
    }
}, {
    "name": "4",
    "value": 7231353492.27,
    "count": 3365,
    "extra": {
        "project": [{
            "tradeCustomerCount": 1436,
            "projectName": "5",
            "tradeCustomerAmount": "5730715019.69"
        }, {
            "tradeCustomerCount": 1083,
            "projectName": "6",
            "tradeCustomerAmount": "1415965309.60"
        }]
    }
}, {
    "name": "7",
    "value": 1062036555.71,
    "count": 1133,
    "extra": {
        "project": [{
            "tradeCustomerCount": 1059,
            "projectName": "8",
            "tradeCustomerAmount": "983960642.35"
        }]
    }
}, {
    "name": "9",
    "value": 215511586.72,
    "count": 767,
    "extra": {
        "project": [{
            "tradeCustomerCount": 750,
            "projectName": "10",
            "tradeCustomerAmount": "202557350.22"
        }, {
            "tradeCustomerCount": 130,
            "projectName": "11",
            "tradeCustomerAmount": "12954236.50"
        }]
    }
}, {
    "name": "12",
    "value": 119211358.54,
    "count": 471,
    "extra": {
        "project": [{
            "tradeCustomerCount": 435,
            "projectName": "13",
            "tradeCustomerAmount": "98256735.14"
        }, {
            "tradeCustomerCount": 99,
            "projectName": "14",
            "tradeCustomerAmount": "20954623.40"
        }]
    }
}];

//父组件 const [data,setData] = useState([]); setTimeout(()=>{ setData(data1) },1000)

yuepy commented 1 year ago

目前感觉可能的原因: 1.formatterVariable更新问题 2.rendItem function没有被正确的加载 尝试使用不带function的简单图表,渲染正常

yuepy commented 1 year ago

已解决。。

1520644927lwt commented 1 year ago

已解决。。

能详细说一下怎么解决的么