React でのデータ視覚化ライブラリの選択、ListChart の例 (リスト切り替え echarts チャート、同様のデータは x 軸のバー)

目次

eチャート

ネイティブ echart+TS

リストチャート.tsx

ListChartUtil.tsx

ReactECharts

React フックは Echarts5 コンポーネント (ts/js) をカプセル化します

比較した

D3

リチャート

eチャート

Echarts は Baidu によって開発されており、中国人の習慣により一致しています。さまざまなタイプのチャートをサポートし、インタラクティブなパフォーマンスが優れています。ドキュメントは詳細でフレンドリーです。強くお勧めします。

欠点がある

  • 初心者にとっては、Echart の設定が難しく、追加の学習コストが必要になる可能性があります。

  • Echarts のカスタマイズ性により、コードが冗長になり、作業負荷と開発時間が増加する可能性があります。

  • 場合によっては、大規模なデータセットをレンダリングするときに Echart が遅くなる可能性があり、パフォーマンスを向上させるために他の最適化が必要になります。

ネイティブ echart+TS

ネイティブ echats の公式ドキュメントと関数は echarts-for-react よりも完全です。

しかし、echarts-for-react は反応サポートに対してよりフレンドリーで使いやすいです。

 

リストチャート.tsx

import React, { useEffect, useRef, useState } from 'react';
import { List, Button} from 'antd';
import { LineChartOutlined, BarChartOutlined } from '@ant-design/icons';
import { ProCard } from '@ant-design/pro-components';
import * as echarts from "echarts";

import './ListChart.css'
import { LIST_NAME, CHART_OPTION,resize,findSubstrIdx } from '../utils/ListChartUtil';
import { ListChartStatus } from "./ListChartStatus";

const ListChart: React.FC<ListChartStatus> = ({ urlPre, proc_datas, board_name }) => {

    const chartRef = useRef<HTMLDivElement>(null); 
    const [selectedIdx, setselectedIdx] = useState<number>(0);
    const [isLine, setIsLine] = React.useState<boolean>(true);
    const proc_list = new Array(proc_datas.length).fill(null).map((val, i) => {
        return proc_datas[i].proc_name;
    });
    let chart: any = null;
    
    useEffect(() => {
        if (chartRef.current) {
            chart = echarts.init(chartRef.current);
            const {option,urlSufs}=getOption(proc_datas[selectedIdx])
            chart.setOption(option);
            resize(chart);
            chart.on('click', isLine ? 'xAxis' : 'series', function (params: any) {
                const clickDate= isLine ? params.value:params.seriesName;
                window.open(urlPre + '/' + urlSufs[findSubstrIdx(urlSufs, clickDate)] + '/index.html', '_blank');
            });
        }  
    }, [chartRef, selectedIdx, isLine]);

    const initDate_UrlSufs=(proc_data:any)=>{
        let urlSufs: string[] = [];
        let dates: string[] = [];
        proc_data.date_list.forEach((date: string, idx: number) => {
            urlSufs.push(date + '/' + proc_data.report_id_list[idx]);
            dates.push(date.substring(5));
        });
        return {dates,urlSufs};
    }
    const  getBarDates=(series:any)=>{
        const barDatas: any = [];
        LIST_NAME.forEach((_, idx) => {
            if (series[idx] && series[idx].length) {
                barDatas.push([LIST_NAME[idx], ...series[idx]])
            }
        })
        return barDatas;
    }
    const getOption=(proc_data:any)=>{
        const {dates,urlSufs}=initDate_UrlSufs(proc_data)
        const series = [proc_data.avg_list, proc_data.sigma3_up_list, proc_data.sigma3_up_target_list, proc_data.sigma3_down_list, proc_data.max_list, proc_data.min_list]
        let option = {  
            tooltip: CHART_OPTION.tooltip,
            legend: CHART_OPTION.legend,
            toolbox: CHART_OPTION.toolbox,
            yAxis: CHART_OPTION.yAxis,
            title: {
                text: proc_data ? board_name + ":" + proc_data.proc_name : board_name,
                subtext: "点击日期可跳转到详情报告",
            },
            xAxis: {
                type: 'category', // 类型为分类轴
                triggerEvent: true, // 是否触发鼠标事件
                data: isLine ? proc_data.date_list.map((date: string, idx: number) => {
                    return dates[idx]
                }) : null,
            },
            series: isLine ? LIST_NAME.map((_, idx) => {
                if (series[idx] && series[idx].length) {
                    return {
                        name: LIST_NAME[idx],
                        type: 'line',
                        data: series[idx],
                        emphasis: {
                            focus: 'series'
                        },
                    }
                }
            }) : dates.map((_, idx) => {
                return {
                    name: dates[idx],
                    type: 'bar',
                    event: 'click',
                    emphasis: {
                        focus: 'series'
                    },
                }
            }),

            dataset: isLine ? null : {
                source: [
                    ['pref', ...dates],
                    ...getBarDates(series)
                ]
            },
        };
        return {option,urlSufs};
    }
    return (<ProCard layout="center"  className="procard" ghost>
        <ProCard colSpan={6} ghost >
            <List
                size="small"
                bordered
                className='procard-list'
                dataSource={proc_list}
                renderItem={(item, index) => <List.Item key={Math.random()} className={selectedIdx === index ? 'selected' :undefined }
                    onClick={() => setselectedIdx(index)}>
                    {item}</List.Item>}
            />
        </ProCard>
        <ProCard colSpan={18} ghost >
            <div className="procard-button" >
                <Button className="ant-btn" icon={<LineChartOutlined />} onClick={() => setIsLine(true)} ></Button>
                <Button className="ant-btn" icon={<BarChartOutlined />} onClick={() => setIsLine(false)}></Button>
            </div>
            <div key={`divChart${Math.random()}`}
                ref={chartRef}
                className='chart'
                style={
   
   {
                    flex: 2,
                    flexDirection:"column",
                    height: "40vh",
                    paddingLeft: "1vw",
                }}
            ></div>
        </ProCard>
    </ProCard>
    )
}
export default ListChart;

リストチャート.css

.procard {
    display: flex;
    padding-top: 10px;
}
.procard-list {
    overflow-y: scroll;
    height: 45vh;
}
.selected {
    background-color: #e6f7ff !important;
  }
.procard-button{
    display: flex;
    justify-content: flex-end;
    padding-right: 7vw;
}

ListChartUtil.tsx

​
export const LIST_NAME = ['avg', '3∑-up', '3∑-up-target', '3∑-down', 'max', 'min']

export const CHART_OPTION = {
  tooltip: {
    trigger: 'axis',
    axisPointer: {
      type: "shadow"
    },
  },
  legend: {
    left: 'center',
    width: '35%',
    selected: {
      'min': false,
      '3∑-down': false,
    }
  },
  toolbox: {
    show: true,
    feature: {
      dataZoom: {
        yAxisIndex: 'none'
      },
      dataView: { readOnly: false },
      //   magicType: { type: ['line'] },
      restore: {},
      saveAsImage: {}
    },
    right: "10%"
  },
  yAxis: {
    type: 'value',
    axisLabel: {
      formatter: '{value}  '
    }
  },
}
const dom: any = [];  //所有echarts图表的数组
/**
 * 当屏幕尺寸变化时,循环数组里的每一项调用resize方法来实现自适应。
 * @param {*} eDom 
 */
export function resize(eDom: any) {
  dom.push(eDom);
  window.onresize = () => {
    dom.forEach((it: any) => {
      it.resize();
    })
  };
}

export function findSubstrIdx(arr: string[], substr: string): number {
  for (let i = 0; i < arr.length; i++) {
    if (arr[i].indexOf(substr) !== -1) {
      return i;
    }
  }
  return -1;
}

​

ReactECharts

React フックは Echarts5 コンポーネント (ts/js) をカプセル化します
 

React+TypeScript は ECharts_react タイプスクリプトをカプセル化します echart_KzXuanCn のブログ-CSDN ブログ

GitHub - hustcc/echarts-for-react: ⛳️ React ラッパー用の Apache ECharts コンポーネント. Apache Echart 用のシンプルな React ラッパー。

比較した

D3

はデータ駆動型のドキュメントベースの JavaScript ライブラリであり、柔軟性が高くカスタマイズ可能ですが、より多くのコーディング作業が必要になります。

リチャート

D3 の強力な描画機能を利用した React カプセル化をベースにしたライブラリで、React をデータ視覚化に使いやすくします。

アドバンテージ

  • Recharts はカスタマイズ オプションの数が少ないため、使いやすいです。

  • React のライフサイクル メソッドと統合して、React アプリケーションへの追加を容易にし、Redux 状態マネージャーをサポートします。

  • 軽量でメモリやCPUへの影響が少ない。

  • 複数のスタイル、カスタムカラー、アニメーションをサポートします。

欠点がある

  • すべてのタイプのチャートをサポートしているわけではなく、さまざまな Echarts もサポートしていません。

  • Echartsに比べて機能が少ない

要約すると、高度にカスタマイズされたチャートを設計する必要があり、十分な開発経験がある場合は、Echarts を使用する方が便利かもしれません。一方、Recharts は、迅速かつ簡単なデータ視覚化タスクに適しており、React アプリケーションに簡単に統合できます。

おすすめ

転載: blog.csdn.net/qq_28838891/article/details/131063427
おすすめ