fix(data-vi): charts flickers (#3836)
This commit is contained in:
		
							parent
							
								
									e95f4ab123
								
							
						
					
					
						commit
						996e89fb14
					
				@ -11,38 +11,38 @@ describe('api', () => {
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    test('setGroup', () => {
 | 
			
		||||
      const charts1 = [new Chart({ name: 'test1', title: 'Test1', component: null })];
 | 
			
		||||
      const charts1 = [new Chart({ name: 'test1', title: 'Test1', Component: null })];
 | 
			
		||||
      plugin.charts.setGroup('group', charts1);
 | 
			
		||||
      expect(plugin.charts.charts.get('group')).toEqual(charts1);
 | 
			
		||||
 | 
			
		||||
      const charts2 = [new Chart({ name: 'test2', title: 'Test2', component: null })];
 | 
			
		||||
      const charts2 = [new Chart({ name: 'test2', title: 'Test2', Component: null })];
 | 
			
		||||
      plugin.charts.setGroup('group', charts2);
 | 
			
		||||
      expect(plugin.charts.charts.get('group')).toEqual(charts2);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    test('addGroup', () => {
 | 
			
		||||
      const charts1 = [new Chart({ name: 'test1', title: 'Test1', component: null })];
 | 
			
		||||
      const charts1 = [new Chart({ name: 'test1', title: 'Test1', Component: null })];
 | 
			
		||||
      plugin.charts.setGroup('group1', charts1);
 | 
			
		||||
      const charts2 = [new Chart({ name: 'test2', title: 'Test2', component: null })];
 | 
			
		||||
      const charts2 = [new Chart({ name: 'test2', title: 'Test2', Component: null })];
 | 
			
		||||
      plugin.charts.addGroup('group2', charts2);
 | 
			
		||||
      expect(plugin.charts.charts.get('group1')).toEqual(charts1);
 | 
			
		||||
      expect(plugin.charts.charts.get('group2')).toEqual(charts2);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    test('add', () => {
 | 
			
		||||
      const charts1 = [new Chart({ name: 'test1', title: 'Test1', component: null })];
 | 
			
		||||
      const charts1 = [new Chart({ name: 'test1', title: 'Test1', Component: null })];
 | 
			
		||||
      plugin.charts.setGroup('group', charts1);
 | 
			
		||||
 | 
			
		||||
      const chart = new Chart({ name: 'test2', title: 'Test2', component: null });
 | 
			
		||||
      const chart = new Chart({ name: 'test2', title: 'Test2', Component: null });
 | 
			
		||||
      plugin.charts.add('group', chart);
 | 
			
		||||
      expect(plugin.charts.charts.get('group').length).toEqual(2);
 | 
			
		||||
      expect(plugin.charts.charts.get('group')[1].name).toEqual('test2');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    test('getChartTypes', () => {
 | 
			
		||||
      const charts1 = [new Chart({ name: 'test1', title: 'Test1', component: null })];
 | 
			
		||||
      const charts1 = [new Chart({ name: 'test1', title: 'Test1', Component: null })];
 | 
			
		||||
      plugin.charts.setGroup('group1', charts1);
 | 
			
		||||
      const charts2 = [new Chart({ name: 'test2', title: 'Test2', component: null })];
 | 
			
		||||
      const charts2 = [new Chart({ name: 'test2', title: 'Test2', Component: null })];
 | 
			
		||||
      plugin.charts.setGroup('group2', charts2);
 | 
			
		||||
      expect(plugin.charts.getChartTypes()).toEqual([
 | 
			
		||||
        {
 | 
			
		||||
@ -69,9 +69,9 @@ describe('api', () => {
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    test('getCharts', () => {
 | 
			
		||||
      const charts1 = [new Chart({ name: 'test1', title: 'Test1', component: null })];
 | 
			
		||||
      const charts1 = [new Chart({ name: 'test1', title: 'Test1', Component: null })];
 | 
			
		||||
      plugin.charts.setGroup('group1', charts1);
 | 
			
		||||
      const charts2 = [new Chart({ name: 'test2', title: 'Test2', component: null })];
 | 
			
		||||
      const charts2 = [new Chart({ name: 'test2', title: 'Test2', Component: null })];
 | 
			
		||||
      plugin.charts.setGroup('group2', charts2);
 | 
			
		||||
      expect(plugin.charts.getCharts()).toEqual({
 | 
			
		||||
        'group1.test1': charts1[0],
 | 
			
		||||
@ -80,9 +80,9 @@ describe('api', () => {
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    test('getChart', () => {
 | 
			
		||||
      const charts1 = [new Chart({ name: 'test1', title: 'Test1', component: null })];
 | 
			
		||||
      const charts1 = [new Chart({ name: 'test1', title: 'Test1', Component: null })];
 | 
			
		||||
      plugin.charts.setGroup('group1', charts1);
 | 
			
		||||
      const charts2 = [new Chart({ name: 'test2', title: 'Test2', component: null })];
 | 
			
		||||
      const charts2 = [new Chart({ name: 'test2', title: 'Test2', Component: null })];
 | 
			
		||||
      plugin.charts.setGroup('group2', charts2);
 | 
			
		||||
      expect(plugin.charts.getChart('group1.test1')).toEqual(charts1[0]);
 | 
			
		||||
      expect(plugin.charts.getChart('group2.test2')).toEqual(charts2[0]);
 | 
			
		||||
@ -90,7 +90,7 @@ describe('api', () => {
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('auto infer', () => {
 | 
			
		||||
    const chart = new Chart({ name: 'test', title: 'Test', component: null });
 | 
			
		||||
    const chart = new Chart({ name: 'test', title: 'Test', Component: null });
 | 
			
		||||
    const fields = [
 | 
			
		||||
      {
 | 
			
		||||
        name: 'price',
 | 
			
		||||
 | 
			
		||||
@ -8,7 +8,7 @@ export class Statistic extends AntdChart {
 | 
			
		||||
    super({
 | 
			
		||||
      name: 'statistic',
 | 
			
		||||
      title: 'Statistic',
 | 
			
		||||
      component: AntdStatistic,
 | 
			
		||||
      Component: AntdStatistic,
 | 
			
		||||
      config: [
 | 
			
		||||
        {
 | 
			
		||||
          property: 'field',
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,7 @@ import { Table as AntdTable } from 'antd';
 | 
			
		||||
 | 
			
		||||
export class Table extends AntdChart {
 | 
			
		||||
  constructor() {
 | 
			
		||||
    super({ name: 'table', title: 'Table', component: AntdTable });
 | 
			
		||||
    super({ name: 'table', title: 'Table', Component: AntdTable });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getProps({ data, fieldProps, general, advanced }: RenderProps) {
 | 
			
		||||
 | 
			
		||||
@ -22,7 +22,7 @@ export type RenderProps = {
 | 
			
		||||
export interface ChartType {
 | 
			
		||||
  name: string;
 | 
			
		||||
  title: string;
 | 
			
		||||
  component: React.FC<any>;
 | 
			
		||||
  Component: React.FC<any>;
 | 
			
		||||
  schema: ISchema;
 | 
			
		||||
  init?: (
 | 
			
		||||
    fields: FieldOption[],
 | 
			
		||||
@ -34,7 +34,7 @@ export interface ChartType {
 | 
			
		||||
    general?: any;
 | 
			
		||||
    advanced?: any;
 | 
			
		||||
  };
 | 
			
		||||
  render: (props: RenderProps) => React.FC<any>;
 | 
			
		||||
  getProps(props: RenderProps): any;
 | 
			
		||||
  getReference?: () => {
 | 
			
		||||
    title: string;
 | 
			
		||||
    link: string;
 | 
			
		||||
@ -44,21 +44,21 @@ export interface ChartType {
 | 
			
		||||
export type ChartProps = {
 | 
			
		||||
  name: string;
 | 
			
		||||
  title: string;
 | 
			
		||||
  component: React.FC<any>;
 | 
			
		||||
  Component: React.FC<any>;
 | 
			
		||||
  config?: Config[];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export class Chart implements ChartType {
 | 
			
		||||
  name: string;
 | 
			
		||||
  title: string;
 | 
			
		||||
  component: React.FC<any>;
 | 
			
		||||
  Component: React.FC<any>;
 | 
			
		||||
  config: Config[];
 | 
			
		||||
  configs = new Map<string, Function>();
 | 
			
		||||
 | 
			
		||||
  constructor({ name, title, component, config }: ChartProps) {
 | 
			
		||||
  constructor({ name, title, Component, config }: ChartProps) {
 | 
			
		||||
    this.name = name;
 | 
			
		||||
    this.title = title;
 | 
			
		||||
    this.component = component;
 | 
			
		||||
    this.Component = Component;
 | 
			
		||||
    this.config = config;
 | 
			
		||||
    this.addConfigs(configs);
 | 
			
		||||
  }
 | 
			
		||||
@ -170,11 +170,4 @@ export class Chart implements ChartType {
 | 
			
		||||
  getProps(props: RenderProps): any {
 | 
			
		||||
    return props;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  render({ data, general, advanced, fieldProps }: RenderProps) {
 | 
			
		||||
    return () =>
 | 
			
		||||
      React.createElement(this.component, {
 | 
			
		||||
        ...this.getProps({ data, general, advanced, fieldProps }),
 | 
			
		||||
      });
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,7 @@ import { ChartType } from '../chart';
 | 
			
		||||
 | 
			
		||||
export class Bar extends G2PlotChart {
 | 
			
		||||
  constructor() {
 | 
			
		||||
    super({ name: 'bar', title: 'Bar Chart', component: G2PlotBar, config: ['isGroup', 'isStack', 'isPercent'] });
 | 
			
		||||
    super({ name: 'bar', title: 'Bar Chart', Component: G2PlotBar, config: ['isGroup', 'isStack', 'isPercent'] });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  init: ChartType['init'] = (fields, { measures, dimensions }) => {
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,7 @@ import lodash from 'lodash';
 | 
			
		||||
 | 
			
		||||
export class DualAxes extends G2PlotChart {
 | 
			
		||||
  constructor() {
 | 
			
		||||
    super({ name: 'dualAxes', title: 'Dual Axes Chart', component: G2DualAxes });
 | 
			
		||||
    super({ name: 'dualAxes', title: 'Dual Axes Chart', Component: G2DualAxes });
 | 
			
		||||
    this.config = [
 | 
			
		||||
      'xField',
 | 
			
		||||
      {
 | 
			
		||||
 | 
			
		||||
@ -2,11 +2,11 @@ import { Chart, ChartProps, ChartType, RenderProps } from '../chart';
 | 
			
		||||
import configs from './configs';
 | 
			
		||||
 | 
			
		||||
export class G2PlotChart extends Chart {
 | 
			
		||||
  constructor({ name, title, component, config }: ChartProps) {
 | 
			
		||||
  constructor({ name, title, Component, config }: ChartProps) {
 | 
			
		||||
    super({
 | 
			
		||||
      name,
 | 
			
		||||
      title,
 | 
			
		||||
      component,
 | 
			
		||||
      Component,
 | 
			
		||||
      config: ['xField', 'yField', 'seriesField', ...(config || [])],
 | 
			
		||||
    });
 | 
			
		||||
    this.addConfigs(configs);
 | 
			
		||||
 | 
			
		||||
@ -7,13 +7,13 @@ export default [
 | 
			
		||||
  new G2PlotChart({
 | 
			
		||||
    name: 'line',
 | 
			
		||||
    title: 'Line Chart',
 | 
			
		||||
    component: Line,
 | 
			
		||||
    Component: Line,
 | 
			
		||||
    config: ['smooth', 'isStack'],
 | 
			
		||||
  }),
 | 
			
		||||
  new G2PlotChart({
 | 
			
		||||
    name: 'area',
 | 
			
		||||
    title: 'Area Chart',
 | 
			
		||||
    component: Area,
 | 
			
		||||
    Component: Area,
 | 
			
		||||
    config: [
 | 
			
		||||
      'smooth',
 | 
			
		||||
      {
 | 
			
		||||
@ -26,16 +26,16 @@ export default [
 | 
			
		||||
  new G2PlotChart({
 | 
			
		||||
    name: 'column',
 | 
			
		||||
    title: 'Column Chart',
 | 
			
		||||
    component: Column,
 | 
			
		||||
    Component: Column,
 | 
			
		||||
    config: ['isGroup', 'isStack', 'isPercent'],
 | 
			
		||||
  }),
 | 
			
		||||
  new G2PlotChart({
 | 
			
		||||
    name: 'bar',
 | 
			
		||||
    title: 'Bar Chart',
 | 
			
		||||
    component: Bar,
 | 
			
		||||
    Component: Bar,
 | 
			
		||||
    config: ['isGroup', 'isStack', 'isPercent'],
 | 
			
		||||
  }),
 | 
			
		||||
  new Pie(),
 | 
			
		||||
  new DualAxes(),
 | 
			
		||||
  new G2PlotChart({ name: 'scatter', title: 'Scatter Chart', component: Scatter }),
 | 
			
		||||
  new G2PlotChart({ name: 'scatter', title: 'Scatter Chart', Component: Scatter }),
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,7 @@ import { ChartType, RenderProps } from '../chart';
 | 
			
		||||
 | 
			
		||||
export class Pie extends G2PlotChart {
 | 
			
		||||
  constructor() {
 | 
			
		||||
    super({ name: 'pie', title: 'Pie Chart', component: G2Pie });
 | 
			
		||||
    super({ name: 'pie', title: 'Pie Chart', Component: G2Pie });
 | 
			
		||||
    this.config = [
 | 
			
		||||
      {
 | 
			
		||||
        property: 'field',
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,7 @@ import {
 | 
			
		||||
  useDesignable,
 | 
			
		||||
} from '@nocobase/client';
 | 
			
		||||
import { Empty, Result, Spin, Typography } from 'antd';
 | 
			
		||||
import React, { useContext } from 'react';
 | 
			
		||||
import React, { memo, useContext } from 'react';
 | 
			
		||||
import { ErrorBoundary } from 'react-error-boundary';
 | 
			
		||||
import { ChartConfigContext } from '../configure';
 | 
			
		||||
import { useData, useFieldTransformer, useFieldsWithAssociation } from '../hooks';
 | 
			
		||||
@ -22,6 +22,8 @@ import { ChartRendererContext } from './ChartRendererProvider';
 | 
			
		||||
import { useChart } from '../chart/group';
 | 
			
		||||
import { ChartDataContext } from '../block/ChartDataProvider';
 | 
			
		||||
const { Paragraph, Text } = Typography;
 | 
			
		||||
import lodash from 'lodash';
 | 
			
		||||
import { Line } from '@ant-design/plots';
 | 
			
		||||
 | 
			
		||||
export const ChartRenderer: React.FC & {
 | 
			
		||||
  Designer: React.FC;
 | 
			
		||||
@ -38,7 +40,7 @@ export const ChartRenderer: React.FC & {
 | 
			
		||||
  const chart = useChart(config?.chartType);
 | 
			
		||||
  const locale = api.auth.getLocale();
 | 
			
		||||
  const transformers = useFieldTransformer(transform, locale);
 | 
			
		||||
  const Component = chart?.render({
 | 
			
		||||
  const chartProps = chart?.getProps({
 | 
			
		||||
    data,
 | 
			
		||||
    general,
 | 
			
		||||
    advanced,
 | 
			
		||||
@ -51,30 +53,27 @@ export const ChartRenderer: React.FC & {
 | 
			
		||||
      return props;
 | 
			
		||||
    }, {}),
 | 
			
		||||
  });
 | 
			
		||||
  const C = chart?.Component;
 | 
			
		||||
 | 
			
		||||
  const C = () =>
 | 
			
		||||
    chart ? (
 | 
			
		||||
  if (!chart) {
 | 
			
		||||
    return <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description={t('Please configure chart')} />;
 | 
			
		||||
  }
 | 
			
		||||
  if (!(data && data.length) && !service.loading) {
 | 
			
		||||
    return <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description={t('No data')} />;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <Spin spinning={service.loading}>
 | 
			
		||||
      <ErrorBoundary
 | 
			
		||||
        onError={(error) => {
 | 
			
		||||
          console.error(error);
 | 
			
		||||
        }}
 | 
			
		||||
        FallbackComponent={ErrorFallback}
 | 
			
		||||
      >
 | 
			
		||||
        <Component />
 | 
			
		||||
        <C {...chartProps} />
 | 
			
		||||
      </ErrorBoundary>
 | 
			
		||||
    ) : (
 | 
			
		||||
      <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description={t('Please configure chart')} />
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
  if (service.loading) {
 | 
			
		||||
    return <Spin />;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (!(data && data.length)) {
 | 
			
		||||
    return <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description={t('No data')} />;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return <C />;
 | 
			
		||||
    </Spin>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
ChartRenderer.Designer = function Designer() {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user