ホームページ  >  記事  >  ウェブフロントエンド  >  echarts を使用して React Native でチャートを描画する方法について話しましょう

echarts を使用して React Native でチャートを描画する方法について話しましょう

青灯夜游
青灯夜游転載
2023-03-16 19:58:012246ブラウズ

React Native でチャートを描画するにはどうすればよいですか?次の記事では、React Native Echarts を使用して実際の電子商取引データ統計ページを開発する方法を紹介します。

echarts を使用して React Native でチャートを描画する方法について話しましょう

日常のニーズに関連するグラフを作成する場合、最もよく使用されるグラフ ライブラリは echarts です。 Web 側の echart のパフォーマンスは非常に成熟しており、ミニ プログラム側にも公式ソリューションが提供されていますが、RN に対する対応するサポートはありません。市場にあるソリューションのほとんどは基本的に Webview に基づいており、私は RN に基づいたソリューションを好みますが、結局のところ、ネイティブ エクスペリエンスは Web エクスペリエンスよりも優れています。

そこで、需要に応えるために @wuba/react-native-echarts をリリースしました。実装原理に興味がある方は、ここを読んでください。

次に @wuba/react-native-echarts を使用して実際のプロジェクトでアプリケーションを作成していきます。スクリーンショットは次のとおりです:

echarts を使用して React Native でチャートを描画する方法について話しましょう

Tips

  • すでに APP パッケージをお持ちの場合は、前のパッケージ化プロセスを無視して、ステップ 4 に直接ジャンプできます。
  • トライアル用の完全なコードは github にあります。アドレス: github.com/iambool/Tes…

詳細な使用プロセスは次のとおりです

1. 開発環境のセットアップ

RN開発環境をローカルにセットアップします構築手順はネット上で公開されているので割愛します。

2. RN プロジェクトの準備

お試しなので、expo を使って TestApp という RN プロジェクトを新規に初期化しました。

npx create-expo-app TestApp

echarts を使用して React Native でチャートを描画する方法について話しましょう

3. アプリ パッケージのビルド

コマンド ラインを使用して、ios android アプリ パッケージを生成します。 iOS の場合は、ここでシミュレーターを使用することをお勧めします (証明書は必要ありません)。Android の場合は、実際のマシンに接続しました

yarn android
yarn ios

パッケージを生成した後、アプリケーションがインストールされたことが電話に認識されると、成功を意味します。

echarts を使用して React Native でチャートを描画する方法について話しましょう

4. 関連する依存関係をインストールする

yarn add @wuba/react-native-echarts echarts
yarn add @shopify/react-native-skia
yarn add react-native-svg

既存のプロジェクトにインストールする場合は、インストール完了後に新しいパッケージを作成する必要があることに注意してください。それ以外の場合は、ネイティブの依存関係が欠落している場合にエラーが報告されます;

5. Skia モードを試す

@wuba/react-native-echarts は 2 つのレンダリング モード (Skia と Svg) をサポートします 、最初に使用してください Skia 簡単なチャートを試してください。これは、次の小さなステップに大別できます。

  • echart、チャート コンポーネント、その他の依存関係を導入する
  • チャート コンポーネントを登録する
  • チャート インスタンスを作成し、チャート構成を設定する(オプション)
  • ページが破棄されるときは、チャート インスタンスを同期的に破棄することを忘れないでください。

具体的なコードは次のとおりです。

import { useRef, useEffect } from 'react';
import { View } from 'react-native';
/**
 * 一、引入echarts依赖,这里先试下折线图
 */
import * as echarts from 'echarts/core';
import { LineChart } from 'echarts/charts';
import { GridComponent } from 'echarts/components';
import { SVGRenderer, SkiaChart } from '@wuba/react-native-echarts';

/**
 * 二、注册需要用到的组件
 * SVGRenderer: 是必须注册的
 * LineChart: 因为用的折线图,所以要引入LineChart(如果不知道该引入哪些组件,就直接看报错,报错说缺什么就加什么)
 * GridComponent: 这个就是报错的时候提示,然后我加的hhh
 */
echarts.use([SVGRenderer, LineChart, GridComponent]);

export default () => {
  const skiaRef = useRef(null); // Ref用于保存图表实例
  useEffect(() => {
    /**
     * 四、图表配置
     */
    const option = {
      xAxis: {
        type: 'category',
        data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
      },
      yAxis: {
        type: 'value',
      },
      series: [
        {
          data: [150, 230, 224, 218, 135, 147, 260],
          type: 'line',
        },
      ],
    };
    let chart;
    if (skiaRef.current) {
      /**
       * 五、初始化图表,指定下宽高
       */
      chart = echarts.init(skiaRef.current, 'light', {
        renderer: 'svg',
        width: 400,
        height: 400,
      });
      chart.setOption(option);
    }
    /**
     * 六、页面关闭后要销毁图表实例
     */
    return () => chart?.dispose();
  }, []);
  return (
    <View className=&#39;index&#39;>
      <SkiaChart ref={skiaRef} />
    </View>
  );
};

書いた後、電話に接続すると、バンドルをリロードすると表示されます。 エラー レポート:

エラー不変違反: requireNativeComponent: "SkiaDomView" が UIManager に見つかりませんでした。

Google で調べたところ、次のように言われました。 ダウングレードを解決する必要がありました。実際には、expo のバージョンに対応する必要があります。依存関係をインストールするときに、次のようなプロンプトが表示されます。プロンプトが表示されたバージョンをインストールするだけです。

echarts を使用して React Native でチャートを描画する方法について話しましょう

そこで、プロンプトに従ってバージョンを変更します。 :

@shopify/react-native-skia@0.1.157
react-native-svg@13.4.0

アプリを再構築した後、アプリは読み込まれましたが、針は刺さりませんでした; (Android はその点をカバーしており、画面幅に適応する必要があるようです)

# iOSAndroid
echarts を使用して React Native でチャートを描画する方法について話しましょう ##################################

6、试用 Svg 模式

写个复杂点的动态排序柱状图,试试 Svg 模式,给 Svg 和 Skia 做个对比,完整代码看这里

// ...此处省略一些不重要的代码

// 注册需要用到的组件,BarChart-柱状图 LegendComponent-图例
echarts.use([SVGRenderer, BarChart, LegendComponent, GridComponent]);

export default () => {
  const skiaRef = useRef(null);
  const svgRef = useRef(null);

  useEffect(() => {
    // Skia模式
    const skiaChartData = getData(); // 生成图表柱状图数据
    let skiaChart;
    let skiaInter;
    if (skiaRef.current) {
      skiaChart = echarts.init(skiaRef.current, &#39;light&#39;, {
        renderer: &#39;svg&#39;,
        width: 300,
        height: 300,
      });
      skiaChart.setOption(getDefaultOption(skiaChartData));
      setTimeout(function () {
        run(skiaChart, skiaChartData);
      }, 0);
      skiaInter = setInterval(function () {
        run(skiaChart, skiaChartData);
      }, 3000);
    }

    // Svg模式
    const svgChartData = getData();
    let svgChart;
    let svgInter;
    if (svgRef.current) {
      svgChart = echarts.init(svgRef.current, &#39;light&#39;, {
        renderer: &#39;svg&#39;,
        width: 300,
        height: 300,
      });
      svgChart.setOption(getDefaultOption(svgChartData));
      setTimeout(function () {
        run(svgChart, svgChartData);
      }, 0);
      svgInter = setInterval(function () {
        run(svgChart, svgChartData);
      }, 3000);
    }

    return () => {
      skiaChart?.dispose();
      svgChart?.dispose();
      // 定时器得清理掉,不然退出页面后还会运行
      clearInterval(skiaInter);
      clearInterval(svgInter);
    };
  }, []);
  return (
    <View>
      <Text>skia如下</Text>
      <SkiaChart ref={skiaRef} />
      <Text>svg如下</Text>
      <SvgChart ref={svgRef} />
    </View>
  );
};

Skia 和 Svg 模式,肉眼看不出明显差别

iOS Android
echarts を使用して React Native でチャートを描画する方法について話しましょう echarts を使用して React Native でチャートを描画する方法について話しましょう

7、封装 Chart 组件

效果不错,不过每次使用都要把一堆东西引进去好烦,先简单封装下吧

import { useRef, useEffect } from &#39;react&#39;;
import * as echarts from &#39;echarts/core&#39;;
import { BarChart, LineChart, PieChart } from &#39;echarts/charts&#39;;
import {
  DataZoomComponent,
  GridComponent,
  LegendComponent,
  TitleComponent,
  ToolboxComponent,
  TooltipComponent,
} from &#39;echarts/components&#39;;
import {
  SVGRenderer,
  SvgChart as _SvgChart,
  SkiaChart as _SkiaChart,
} from &#39;@wuba/react-native-echarts&#39;;
import { Dimensions } from &#39;react-native&#39;;

// 注册需要用到的组件
echarts.use([
  DataZoomComponent,
  SVGRenderer,
  BarChart,
  GridComponent,
  LegendComponent,
  ToolboxComponent,
  TooltipComponent,
  TitleComponent,
  PieChart,
  LineChart,
]);

// 图表默认宽高
const CHART_WIDTH = Dimensions.get(&#39;screen&#39;).width; // 默认用手机屏幕宽度
const CHART_HEIGHT = 300;

const Chart = ({
  option,
  onInit,
  width = CHART_WIDTH,
  height = CHART_HEIGHT,
  ChartComponent,
}) => {
  const chartRef = useRef(null);

  useEffect(() => {
    let chart;
    if (chartRef.current) {
      chart = echarts.init(chartRef.current, &#39;light&#39;, {
        renderer: &#39;svg&#39;,
        width,
        height,
      });
      option && chart.setOption(option);
      onInit?.(chart);
    }
    return () => chart?.dispose();
  }, [option]);
  return <ChartComponent ref={chartRef} />;
};

const SkiaChart = (props) => <Chart {...props} ChartComponent={_SkiaChart} />;
const SvgChart = (props) => <Chart {...props} ChartComponent={_SvgChart} />;
// 对外只暴露这哥俩就行
export { SkiaChart, SvgChart };

8、多个图表使用

封装好了,咱就写个多图表同时使用的页面看看效果。这里写了个“电商数据分析”页面,分别有折线图、柱状图、饼图。下方是主要代码,用的 svg 模式,详细代码见这里

// 页面代码
import { SkiaChart } from &#39;../../components/Chart&#39;;
import { ScrollView, Text, View } from &#39;react-native&#39;;
import { StatusBar } from &#39;expo-status-bar&#39;;
import { useCallback, useEffect, useState } from &#39;react&#39;;
import {
  defaultActual,
  lineOption,
  salesStatus,
  salesVolume,
  userAnaly,
  getLineData,
} from &#39;./contants&#39;;
import styles from &#39;./styles&#39;;
// 开启图表loading
const showChartLoading = (chart) =>
  chart.showLoading(&#39;default&#39;, {
    maskColor: &#39;#305d9e&#39;,
  });
// 关闭图表loading
const hideChartLoading = (chart) => chart.hideLoading();

export default () => {
  const [actual, setActual] = useState(defaultActual); // 记录实时数据

  useEffect(() => {
    // 假设循环请求数据
    const interv = setInterval(() => {
      const newActual = [];
      for (let it of actual) {
        newActual.push({
          ...it,
          num: it.num + Math.floor((Math.random() * it.num) / 100),
        });
      }
      setActual(newActual);
    }, 200);
    return () => clearInterval(interv);
  }, [actual]);

  const onInitLineChart = useCallback((myChart) => {
    showChartLoading(myChart);
    // 模拟数据请求
    setTimeout(() => {
      myChart.setOption({
        series: getLineData,
      });
      hideChartLoading(myChart);
    }, 1000);
  }, []);

  const onInitUserChart = useCallback((myChart) => {
    // 模拟数据请求,跟onInitLineChart类似
  }, []);
  const onInitSaleChart = useCallback((myChart) => {
    // 模拟数据请求,跟onInitLineChart类似
  }, []);
  const onInitStatusChart = useCallback((myChart) => {
    // 模拟数据请求,跟onInitLineChart类似
  }, []);

  const chartList = [
    [&#39;订单走势&#39;, lineOption, onInitLineChart],
    [&#39;用户统计&#39;, userAnaly, onInitUserChart],
    [&#39;各品类销售统计&#39;, salesVolume, onInitSaleChart],
    [&#39;订单状态统计&#39;, salesStatus, onInitStatusChart],
  ];

  return (
    <ScrollView style={styles.index}>
      <StatusBar style=&#39;light&#39; />
      <View>
        <View style={styles.index_panel_header}>
          <Text style={styles.index_panel_title}>实时数据</Text>
        </View>
        <View style={styles.index_panel_content}>
          {actual.map(({ title, num, unit }) => (
            <View key={title} style={styles.sale_item}>
              <View style={styles.sale_item_cell}>
                <Text style={styles.sale_item_text}>{title}</Text>
              </View>
              <View style={[styles.sale_item_cell, styles.num]}>
                <Text style={styles.sale_item_num}>{num}</Text>
              </View>
              <View style={[styles.sale_item_cell, styles.unit]}>
                <Text style={styles.sale_item_text}>{unit}</Text>
              </View>
            </View>
          ))}
        </View>
      </View>
      {chartList.map(([title, data, callback]) => (
        <View key={title}>
          <View style={styles.index_panel_header}>
            <Text style={styles.index_panel_title}>{title}</Text>
          </View>
          <View style={styles.index_panel_content}>
            <SkiaChart option={data} onInit={callback} />
          </View>
        </View>
      ))}
    </ScrollView>
  );
};

重新加载 bundle,看看效果图

iOS Android
echarts を使用して React Native でチャートを描画する方法について話しましょう

渲染出来后,iOS 上交互很丝滑,安卓上交互时感觉偶尔会有卡顿(不会是因为我手机太差吧…)。

再换 Skia 模式看看

echarts を使用して React Native でチャートを描画する方法について話しましょう

emmm 虽然可以,但是好像中文不能正常显示,安卓上中文都没有显示,iOS 则是乱码。看了下文档,目前 skia 在安卓端还不支持中文,在 iOS 端可以通过设置字体为 'PingFang SC'显示中文,比如:

const option = {
  title: {
    text: &#39;我是中文&#39;,
    textStyle: {
      fontFamily: &#39;PingFang SC&#39;, // 指定字体类型
    },
  },
};

但是每个显示中文的地方都要设置字体……那还是先用 svg 吧,我懒。

总结

使用了一段时间后,我总结了下:

  • 支持度上,@wuba/react-native-echarts 除了 GL 系列、地图类图表还不支持外,其余类型的图表都支持,对于日常业务来说已经非常 enough 了。echarts 各种类型的图表实现,都可以在taro-playground上找到;
  • 交互上,iOS 很丝滑,安卓有时会出现掉帧的情况;
  • 性能上,还挺好的。
    • 个人试了下,不是超大数据量就不会有什么问题,但是数据量太大的时候(比如画大数据量的热力图),渲染速度明显下降了很多,这是一个等待官方去优化的点。
    • 另外页面内图表多的话,真机调试时加载速度会变慢,建议先用模拟器。
  • 中文支持,Svg 模式支持中文,但 Skia 模式目前还不可以。

(学习视频分享:vuejs入门教程编程基础视频

以上がecharts を使用して React Native でチャートを描画する方法について話しましょうの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.cnで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。