VChart icon indicating copy to clipboard operation
VChart copied to clipboard

我在使用react-vchart,无法通过更新props更新图表的3d配置

Open tacit0428 opened this issue 11 months ago • 14 comments

您好,代码如下所示(不好意思不知道为什么乱了),我在父组件更新了props.enable3d,通过useEffect也观察到了props.enable3d的更新,但是图表组件并没有任何变化。 ` function AreaChart(props) {

const [spec, setSpec] = useState({
  type: 'area',
  data: props.dataConfig.data,
  ...
})

const [options, setOptions] = useState({
  options3d: {
      enable: true,
      enableView3dTransform: props.enable3d,
  },

})

React.useEffect(()=>{
  setOptions({
    options3d: {
        enable: true,
        enableView3dTransform: props.enable3d,
        ...
    }
})
},[props.enable3d])

return (
    <VChart
      spec={spec}
      options={options}
      className={props.chartname}
    />
);

}`

tacit0428 avatar Mar 18 '24 14:03 tacit0428

@tacit0428 请提供一下完整的代码,复现问题哦

xile611 avatar Mar 19 '24 06:03 xile611

您好,第一块代码是子组件,第二块代码是使用该子组件。我这边的问题是当创建组件时,options.options3d.enableView3dTransform设置为false,点击rotate希望触发更新该值为true,但图表没有任何反应。

定义AreaChart:

import React, { useState } from 'react';
import { VChart } from '@visactor/react-vchart';

function AreaChart(props) {
    const [spec, setSpec] = useState({
      type: 'area',
      data: props.dataConfig.data,
      xField: props.dataConfig.xField,
      yField: props.dataConfig.yField,
      zField: props.dataConfig.zField,
      seriesField: props.dataConfig.seriesField,
      title: {
        visible: false,
        text: 'Stacked area chart of cosmetic products sales'
      },
      axes: [
        {
          orient: 'bottom',
          mode: '3d',
          domainLine: { 
              visible: false,
              style: { stroke: '#000' } 
          },
          tick: {
            visible:false,
            style: { stroke: '#000' }
          },
          label: {
              visible: false
          }
        },
        {
          orient: 'left',
          mode: '3d',
          domainLine: { visible: false },
          tick: { visible: false },
          label: {
            style: {
              fill: 'rgb(162, 162, 162)'
            }
          },
          grid: {
            visible:false,
            style: {
              lineDash: [0],
              stroke: 'rgb(231, 231, 231)'
            }
          }
        },
        {
          orient: 'z',
          mode: '3d',
          type: 'band',
          label: { visible:false },
          domainLine: { visible: false },
          grid: { visible: false },
          width: 200,
          height: 500,
          depth: 100
        }
      ],
      tooltip: {
        visible: false,
      },
      point: {
        visible: false
      },
      hover: {enable: false},
      select: {enable: false},
      crosshair: {
        xField: {
          visible: false,
        },
      },
      stack: false,
      legends: [{ visible: false }],
      width: props.styleConfig.width,
      height: props.styleConfig.height,
      background: 'rgba(0,0,0,0)'
    })
    const [options, setOptions] = useState({
      options3d: {
          enable: true,
          enableView3dTransform: false,
          alpha: 0,
          beta: 0,
          fieldRatio: 25,
          fieldDepth: 500,
          center: { 
            x: Math.round(props.styleConfig.width/2), 
            y: Math.round(props.styleConfig.height/2) 
          }
      }
  })
   
    React.useEffect(()=>{
      setOptions({
        options3d: {
            enable: true,
            enableView3dTransform: props.enable3d,
            alpha: 0,
            beta: 0,
            fieldRatio: 25,
            fieldDepth: 500,
            center: { 
              x: Math.round(props.styleConfig.width/2), 
              y: Math.round(props.styleConfig.height/2) 
            }
        }
    })
    },[props.enable3d])

    return (
        <VChart
          spec={spec}
          options={options}
          className={props.chartname}
        />
    );
}

export default AreaChart;

使用AreaChart:

import React, {Component, createRef} from 'react'
import AreaChart from '../../charts/areachart';

class ChartTest extends Component {
    constructor(props) {
        super(props);
        this.dataConfig = {
            data: {
                values: [
                  { type: 'Nail polish', country: 'Africa', value: 4229 },
                  { type: 'Nail polish', country: 'EU', value: 4376 },
                  { type: 'Nail polish', country: 'China', value: 3054 },
                  { type: 'Nail polish', country: 'USA', value: 12814 },
                  { type: 'Eyebrow pencil', country: 'Africa', value: 3932 },
                  { type: 'Eyebrow pencil', country: 'EU', value: 3987 },
                  { type: 'Eyebrow pencil', country: 'China', value: 5067 },
                  { type: 'Eyebrow pencil', country: 'USA', value: 13012 },
                  { type: 'Rouge', country: 'Africa', value: 5221 },
                  { type: 'Rouge', country: 'EU', value: 3574 },
                  { type: 'Rouge', country: 'China', value: 7004 },
                  { type: 'Rouge', country: 'USA', value: 11624 },
                  { type: 'Lipstick', country: 'Africa', value: 9256 },
                  { type: 'Lipstick', country: 'EU', value: 4376 },
                  { type: 'Lipstick', country: 'China', value: 9054 },
                  { type: 'Lipstick', country: 'USA', value: 8814 },
                  { type: 'Eyeshadows', country: 'Africa', value: 3308 },
                  { type: 'Eyeshadows', country: 'EU', value: 4572 },
                  { type: 'Eyeshadows', country: 'China', value: 12043 },
                  { type: 'Eyeshadows', country: 'USA', value: 12998 },
                  { type: 'Eyeliner', country: 'Africa', value: 5432 },
                  { type: 'Eyeliner', country: 'EU', value: 3417 },
                  { type: 'Eyeliner', country: 'China', value: 15067 },
                  { type: 'Eyeliner', country: 'USA', value: 12321 },
                  { type: 'Foundation', country: 'Africa', value: 13701 },
                  { type: 'Foundation', country: 'EU', value: 5231 },
                  { type: 'Foundation', country: 'China', value: 10119 },
                  { type: 'Foundation', country: 'USA', value: 10342 },
                  { type: 'Lip gloss', country: 'Africa', value: 4008 },
                  { type: 'Lip gloss', country: 'EU', value: 4572 },
                  { type: 'Lip gloss', country: 'China', value: 12043 },
                  { type: 'Lip gloss', country: 'USA', value: 22998 },
                  { type: 'Mascara', country: 'Africa', value: 18712 },
                  { type: 'Mascara', country: 'EU', value: 6134 },
                  { type: 'Mascara', country: 'China', value: 10419 },
                  { type: 'Mascara', country: 'USA', value: 11261 }
                ]
            },
            xField: 'type',
            yField: 'value',
            zField: 'country',
            seriesField: 'country'
        }
        this.styleConfig = {
            width: 400,
            height: 400
        }
        this.state = {
            enable3d: false,
        }
    }

    rotate = () => {
        console.log('rotate')
        this.setState({
            enable3d: true
        })      
    }


    render() {
        return (
            <div>
                <AreaChart type='area' dataConfig={this.dataConfig} styleConfig={this.styleConfig} enable3d={this.state.enable3d} chartname={'chart'}/>
                <input type="button" value="rotate"  id="rotate" onClick={this.rotate}/>
            </div>
        )
    }
}

export default ChartTest

tacit0428 avatar Mar 19 '24 08:03 tacit0428

@tacit0428 options 和 spec 不一致,不支持更新,只能初始化的时候设置一次

建议你可以在enable3d 切换的时候,给<VChart /> 添加不同的key,实现创建新的实例的效果

<VChart
  key={props.enable3d ? '3dChart' : '2dChart'}
          spec={spec}
          options={options}
          className={props.chartname}
        />

xile611 avatar Mar 19 '24 08:03 xile611

@tacit0428 options 和 spec 不一致,不支持更新,只能初始化的时候设置一次

建议你可以在enable3d 切换的时候,给<VChart /> 添加不同的key,实现创建新的实例的效果

<VChart
  key={props.enable3d ? '3dChart' : '2dChart'}
          spec={spec}
          options={options}
          className={props.chartname}
        />

谢谢,不过请问如果要经常更新options的话要怎么办呢,我想经常调整角度,有时候也会调整options.options3d.alpha/beta,调整次数很多的情况下,反复生成新实例感觉不方便,有什么解决方法吗?

tacit0428 avatar Mar 21 '24 01:03 tacit0428

@tacit0428 options 和 spec 不一致,不支持更新,只能初始化的时候设置一次 建议你可以在enable3d 切换的时候,给<VChart /> 添加不同的key,实现创建新的实例的效果

<VChart
  key={props.enable3d ? '3dChart' : '2dChart'}
          spec={spec}
          options={options}
          className={props.chartname}
        />

谢谢,不过请问如果要经常更新options的话要怎么办呢,我想经常调整角度,有时候也会调整options.options3d.alpha/beta,调整次数很多的情况下,反复生成新实例感觉不方便,有什么解决方法吗?

  1. 可以在onReady事件中获取vchart实例
  2. 调用api更新角度
const stage = vchart.getStage();
stage.set3dOptions({center: { x: 500, y: 250 }, alpha: 0.2} // 这里传参数就行);
stage.renderNextFrame();

neuqzxy avatar Mar 21 '24 03:03 neuqzxy

2. api更新角度

@tacit0428 如果着急的话,可以先调用上面提供的底层API; 这边我们会封装一个更新3d配置的API CC @neuqzxy

xile611 avatar Mar 21 '24 03:03 xile611

@tacit0428 options 和 spec 不一致,不支持更新,只能初始化的时候设置一次 建议你可以在enable3d 切换的时候,给<VChart /> 添加不同的key,实现创建新的实例的效果

<VChart
  key={props.enable3d ? '3dChart' : '2dChart'}
          spec={spec}
          options={options}
          className={props.chartname}
        />

谢谢,不过请问如果要经常更新options的话要怎么办呢,我想经常调整角度,有时候也会调整options.options3d.alpha/beta,调整次数很多的情况下,反复生成新实例感觉不方便,有什么解决方法吗?

  1. 可以在onReady事件中获取vchart实例
  2. 调用api更新角度
const stage = vchart.getStage();
stage.set3dOptions({center: { x: 500, y: 250 }, alpha: 0.2} // 这里传参数就行);
stage.renderNextFrame();

我尝试了下您说的方法,我在onready里确实可以拿到实例,但是我把这个实例保存到state中,再次调用会发现为空 image

tacit0428 avatar Mar 21 '24 07:03 tacit0428

用会发

你的调用逻辑是什么?最好给一个在线demo

xile611 avatar Mar 26 '24 08:03 xile611

@xile611 @neuqzxy 你好,我的使用方法是这样的,但是点击change后,我发现图表并没有更新

function AreaChart(props) {
    const [spec, setSpec] = useState({
      type: 'area',
      data: {
                values: [
                  { type: 'Nail polish', country: 'Africa', value: 4229 },
                  { type: 'Nail polish', country: 'EU', value: 4376 },
                  { type: 'Nail polish', country: 'China', value: 3054 },
                  { type: 'Nail polish', country: 'USA', value: 12814 },
                  { type: 'Eyebrow pencil', country: 'Africa', value: 3932 },
                  { type: 'Eyebrow pencil', country: 'EU', value: 3987 },
                  { type: 'Eyebrow pencil', country: 'China', value: 5067 },
                  { type: 'Eyebrow pencil', country: 'USA', value: 13012 },
                  { type: 'Rouge', country: 'Africa', value: 5221 },
                  { type: 'Rouge', country: 'EU', value: 3574 },
                  { type: 'Rouge', country: 'China', value: 7004 },
                  { type: 'Rouge', country: 'USA', value: 11624 },
                  { type: 'Lipstick', country: 'Africa', value: 9256 },
                  { type: 'Lipstick', country: 'EU', value: 4376 },
                  { type: 'Lipstick', country: 'China', value: 9054 },
                  { type: 'Lipstick', country: 'USA', value: 8814 },
                  { type: 'Eyeshadows', country: 'Africa', value: 3308 },
                  { type: 'Eyeshadows', country: 'EU', value: 4572 },
                  { type: 'Eyeshadows', country: 'China', value: 12043 },
                  { type: 'Eyeshadows', country: 'USA', value: 12998 },
                  { type: 'Eyeliner', country: 'Africa', value: 5432 },
                  { type: 'Eyeliner', country: 'EU', value: 3417 },
                  { type: 'Eyeliner', country: 'China', value: 15067 },
                  { type: 'Eyeliner', country: 'USA', value: 12321 },
                  { type: 'Foundation', country: 'Africa', value: 13701 },
                  { type: 'Foundation', country: 'EU', value: 5231 },
                  { type: 'Foundation', country: 'China', value: 10119 },
                  { type: 'Foundation', country: 'USA', value: 10342 },
                  { type: 'Lip gloss', country: 'Africa', value: 4008 },
                  { type: 'Lip gloss', country: 'EU', value: 4572 },
                  { type: 'Lip gloss', country: 'China', value: 12043 },
                  { type: 'Lip gloss', country: 'USA', value: 22998 },
                  { type: 'Mascara', country: 'Africa', value: 18712 },
                  { type: 'Mascara', country: 'EU', value: 6134 },
                  { type: 'Mascara', country: 'China', value: 10419 },
                  { type: 'Mascara', country: 'USA', value: 11261 }
                ]
            },
      xField: 'type',
      yField: 'value',
      zField: 'country',
      seriesField: 'country',
      title: {
        visible: false,
        text: 'Stacked area chart of cosmetic products sales'
      },
      axes: [
        {
          orient: 'bottom',
          mode: '3d',
          domainLine: { 
              visible: false,
              style: { stroke: '#000' } 
          },
          tick: {
            visible:false,
            style: { stroke: '#000' }
          },
          label: {
              visible: false
          }
        },
        {
          orient: 'left',
          mode: '3d',
          domainLine: { visible: false },
          tick: { visible: false },
          label: {
            style: {
              fill: 'rgb(162, 162, 162)'
            }
          },
          grid: {
            visible:false,
            style: {
              lineDash: [0],
              stroke: 'rgb(231, 231, 231)'
            }
          }
        },
        {
          orient: 'z',
          mode: '3d',
          type: 'band',
          label: { visible:false },
          domainLine: { visible: false },
          grid: { visible: false },
          width: 200,
          height: 500,
          depth: 100
        }
      ],
      tooltip: {
        visible: false,
      },
      point: {
        visible: false
      },
      hover: {enable: false},
      select: {enable: false},
      crosshair: {
        xField: {
          visible: false,
        },
      },
      stack: false,
      legends: [{ visible: false }],
      width: props.styleConfig.width,
      height: props.styleConfig.height,
      background: 'rgba(0,0,0,0)'
    })
    const [options, setOptions] = useState({
      options3d: {
          enable: true,
          enableView3dTransform: true,
          alpha: 0,
          beta: 0,
          fieldRatio: 25,
          fieldDepth: 500,
          center: { 
            x: 200, 
            y: 200 
          }
      }
  })
    const [stage, setStage] = useState({})

    const onChangeStage = ()=>{
      stage.set3dOptions({
        enableView3dTransform: false,
      })
      stage.renderNextFrame()
      console.log(stage)
    }

    const onChartReady = (chart)=>{
      const getstage = chart.getStage()
      setStage(getstage)
    }

    return (
      <div>
        <VChart
          spec={spec}
          options={options}
          className={'testchart'}
          onReady={onChartReady}
        />
        <input type="button" value="change" onClick={onChangeStage}/>
      </div>
    );
}

export default AreaChart;

tacit0428 avatar Apr 07 '24 11:04 tacit0428

@xile611 @neuqzxy 你好,我的使用方法是这样的,但是点击change后,我发现图表并没有更新

function AreaChart(props) {
    const [spec, setSpec] = useState({
      type: 'area',
      data: {
                values: [
                  { type: 'Nail polish', country: 'Africa', value: 4229 },
                  { type: 'Nail polish', country: 'EU', value: 4376 },
                  { type: 'Nail polish', country: 'China', value: 3054 },
                  { type: 'Nail polish', country: 'USA', value: 12814 },
                  { type: 'Eyebrow pencil', country: 'Africa', value: 3932 },
                  { type: 'Eyebrow pencil', country: 'EU', value: 3987 },
                  { type: 'Eyebrow pencil', country: 'China', value: 5067 },
                  { type: 'Eyebrow pencil', country: 'USA', value: 13012 },
                  { type: 'Rouge', country: 'Africa', value: 5221 },
                  { type: 'Rouge', country: 'EU', value: 3574 },
                  { type: 'Rouge', country: 'China', value: 7004 },
                  { type: 'Rouge', country: 'USA', value: 11624 },
                  { type: 'Lipstick', country: 'Africa', value: 9256 },
                  { type: 'Lipstick', country: 'EU', value: 4376 },
                  { type: 'Lipstick', country: 'China', value: 9054 },
                  { type: 'Lipstick', country: 'USA', value: 8814 },
                  { type: 'Eyeshadows', country: 'Africa', value: 3308 },
                  { type: 'Eyeshadows', country: 'EU', value: 4572 },
                  { type: 'Eyeshadows', country: 'China', value: 12043 },
                  { type: 'Eyeshadows', country: 'USA', value: 12998 },
                  { type: 'Eyeliner', country: 'Africa', value: 5432 },
                  { type: 'Eyeliner', country: 'EU', value: 3417 },
                  { type: 'Eyeliner', country: 'China', value: 15067 },
                  { type: 'Eyeliner', country: 'USA', value: 12321 },
                  { type: 'Foundation', country: 'Africa', value: 13701 },
                  { type: 'Foundation', country: 'EU', value: 5231 },
                  { type: 'Foundation', country: 'China', value: 10119 },
                  { type: 'Foundation', country: 'USA', value: 10342 },
                  { type: 'Lip gloss', country: 'Africa', value: 4008 },
                  { type: 'Lip gloss', country: 'EU', value: 4572 },
                  { type: 'Lip gloss', country: 'China', value: 12043 },
                  { type: 'Lip gloss', country: 'USA', value: 22998 },
                  { type: 'Mascara', country: 'Africa', value: 18712 },
                  { type: 'Mascara', country: 'EU', value: 6134 },
                  { type: 'Mascara', country: 'China', value: 10419 },
                  { type: 'Mascara', country: 'USA', value: 11261 }
                ]
            },
      xField: 'type',
      yField: 'value',
      zField: 'country',
      seriesField: 'country',
      title: {
        visible: false,
        text: 'Stacked area chart of cosmetic products sales'
      },
      axes: [
        {
          orient: 'bottom',
          mode: '3d',
          domainLine: { 
              visible: false,
              style: { stroke: '#000' } 
          },
          tick: {
            visible:false,
            style: { stroke: '#000' }
          },
          label: {
              visible: false
          }
        },
        {
          orient: 'left',
          mode: '3d',
          domainLine: { visible: false },
          tick: { visible: false },
          label: {
            style: {
              fill: 'rgb(162, 162, 162)'
            }
          },
          grid: {
            visible:false,
            style: {
              lineDash: [0],
              stroke: 'rgb(231, 231, 231)'
            }
          }
        },
        {
          orient: 'z',
          mode: '3d',
          type: 'band',
          label: { visible:false },
          domainLine: { visible: false },
          grid: { visible: false },
          width: 200,
          height: 500,
          depth: 100
        }
      ],
      tooltip: {
        visible: false,
      },
      point: {
        visible: false
      },
      hover: {enable: false},
      select: {enable: false},
      crosshair: {
        xField: {
          visible: false,
        },
      },
      stack: false,
      legends: [{ visible: false }],
      width: props.styleConfig.width,
      height: props.styleConfig.height,
      background: 'rgba(0,0,0,0)'
    })
    const [options, setOptions] = useState({
      options3d: {
          enable: true,
          enableView3dTransform: true,
          alpha: 0,
          beta: 0,
          fieldRatio: 25,
          fieldDepth: 500,
          center: { 
            x: 200, 
            y: 200 
          }
      }
  })
    const [stage, setStage] = useState({})

    const onChangeStage = ()=>{
      stage.set3dOptions({
        enableView3dTransform: false,
      })
      stage.renderNextFrame()
      console.log(stage)
    }

    const onChartReady = (chart)=>{
      const getstage = chart.getStage()
      setStage(getstage)
    }

    return (
      <div>
        <VChart
          spec={spec}
          options={options}
          className={'testchart'}
          onReady={onChartReady}
        />
        <input type="button" value="change" onClick={onChangeStage}/>
      </div>
    );
}

export default AreaChart;

@xile611 @neuqzxy 请帮帮看一下这个问题,谢谢~我这边逻辑很简单,就是在onReady里getStage之后保存到状态中,然后点击某按钮时对stage进行set和render,但是没有效果。麻烦您看看是不是我的使用方法出错了,感谢

tacit0428 avatar Apr 10 '24 08:04 tacit0428

抱歉现在才回复,我新建了一个项目,看到这个已经是生效了,点击change之后图表已经发生了变化 @tacit0428

neuqzxy avatar May 09 '24 13:05 neuqzxy

如果github不好消息沟通,可以加飞书群沟通 @tacit0428

neuqzxy avatar May 09 '24 13:05 neuqzxy

如果github不好消息沟通,可以加飞书群沟通 @tacit0428

请问怎么加飞书群呢

tacit0428 avatar May 10 '24 03:05 tacit0428

如果github不好消息沟通,可以加飞书群沟通 @tacit0428

请问怎么加飞书群呢

image @tacit0428

xuanhun avatar May 10 '24 03:05 xuanhun