paint-brush
2023 年に React Native Charting を行うための最良の方法@zhiqingchen
4,000 測定値
4,000 測定値

2023 年に React Native Charting を行うための最良の方法

zhiqingchen13m2023/03/30
Read on Terminal Reader

長すぎる; 読むには

チャート関連の要件を記述するために最もよく使用されるチャート ライブラリは、**echarts** です。 Web サイトでの echarts のパフォーマンスは非常に成熟しており、公式のソリューションはアプレット側に提供されていますが、RN には対応するサポートがありません。市場では、ほとんどの検索は依然として webview 実装の本質に基づいており、私は RN ベースのプログラムを好みます。
featured image - 2023 年に React Native Charting を行うための最良の方法
zhiqingchen HackerNoon profile picture
0-item
1-item

チャート関連の要件を記述するために最もよく使用されるチャート ライブラリは、 echartsです。


Web サイトでの echarts のパフォーマンスは非常に成熟しており、公式のソリューションはアプレット側に提供されていますが、RN には対応するサポートがありません。市場では、ほとんどの検索は依然として webview 実装の本質に基づいており、私は RN ベースのプログラムを好みます。結局、ネイティブ エクスペリエンスは Web よりも優れています。


後で、 @wuba/react-native-echarts が私のニーズを満たすのを見つけたので、試してみてください。結果は悪くありません。実装原理に興味のある方はこちら

チップ

  • APP パッケージが既にある場合は、前のパッケージ化プロセスを無視して、手順 4 から直接開始できます。
  • 試用版の完全なコードは、https: //github.com/iambool/TestAppの GitHub にあります。

使用する手順は次のとおりです。

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

これは、既にインターネット上で利用可能なローカル RN 開発環境を構築するプロセスなので、ここでは繰り返しません。 Googleで検索できます:)

ステップ 2.RN プロジェクトの作成

試用だったので、expo を使用して、TestApp という rn プロジェクトを新しく初期化しました。

 npx create-expo-app TestApp 

TestApp を作成する

ステップ 3. モバイル デバイスでのアプリの構築

コマンド ラインで ios および android アプリ パッケージを生成します。


エミュレーターの使用には iOS をお勧めします (証明書を一致させる必要はありません)。 Android では、実機に接続していました。


 yarn android yarn ios


パッケージを生成すると、以下のようなアプリが既に電話にインストールされているため、成功しています。

写真

ステップ 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'; /** * 1. Import the echarts dependency, this example first tries the line chart */ import * as echarts from 'echarts/core'; import { LineChart } from 'echarts/charts'; import { GridComponent } from 'echarts/components'; import { SVGRenderer, SkiaChart } from '@wuba/react-native-echarts'; /** * 2. Register the required components * SVGRenderer: it is required to register * LineChart: because we want to show the line chart, we have to import LineChart * - If you don't know which components to import, just look at the error report and add whatever the error says is missing * GridComponent: This is the prompt when the error is reported, and then I added the, ha ha */ echarts.use([SVGRenderer, LineChart, GridComponent]); export default () => { const skiaRef = useRef(null); // Ref for saving chart instances useEffect(() => { /** * 3. chart option */ 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) { /** * 4. Initialize the chart, specifying the lower width and height */ chart = echarts.init(skiaRef.current, 'light', { renderer: 'svg', width: 400, height: 400, }); chart.setOption(option); } /** * 5. To destroy the chart instance after the page is closed */ return () => chart?.dispose(); }, []); return ( <View className='index'> <SkiaChart ref={skiaRef} /> </View> ); };


コードを書き、電話を振ってバンドル パッケージをリロードすると、エラーが報告されました。

ERROR Invariant Violation: requireNativeComponent: "SkiaDomView" が UIManager に見つかりませんでした。


私はそれをグーグルで調べたところ、バージョンのダウングレードが必要であると言われています。 expo バージョンに対応している必要があります。依存関係をインストールするときに同様のプロンプトが表示され、プロンプトされたバージョンをインストールすると問題ありません。

警告

そのため、指示に従い、バージョンをダウングレードしました。

 @shopify/[email protected] [email protected]

アプリを再構築した後、ロードされました。これは良かったです。 (ただし、Android はその点をカバーしています。画面幅は適応する必要があるようです。)

iOS

アンドロイド

iOS

アンドロイド

ステップ 6. Svg モデルを試す

Svg モードでより複雑な動的ソート棒グラフを作成し、Svg と Skia を比較します。完全なコードはこちら

 // ...Some unimportant code is omitted here // Register the required components, such as BarChart and LegendComponent echarts.use([SVGRenderer, BarChart, LegendComponent, GridComponent]); export default () => { const skiaRef = useRef(null); const svgRef = useRef(null); useEffect(() => { // Skia mode const skiaChartData = getData(); // Generate chart bar data let skiaChart; let skiaInter; if (skiaRef.current) { skiaChart = echarts.init(skiaRef.current, 'light', { renderer: 'svg', width: 300, height: 300, }); skiaChart.setOption(getDefaultOption(skiaChartData)); setTimeout(function () { run(skiaChart, skiaChartData); }, 0); skiaInter = setInterval(function () { run(skiaChart, skiaChartData); }, 3000); } // Svg mode const svgChartData = getData(); let svgChart; let svgInter; if (svgRef.current) { svgChart = echarts.init(svgRef.current, 'light', { renderer: 'svg', 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(); // The timer has to be cleaned up, otherwise it will still run after exiting the page clearInterval(skiaInter); clearInterval(svgInter); }; }, []); return ( <View> <Text>skia</Text> <SkiaChart ref={skiaRef} /> <Text>svg</Text> <SvgChart ref={svgRef} /> </View> ); };


この 2 つのモードの違いは、自分の目ではわかりません。

iOS

アンドロイド

写真

写真

手順 7. チャート コンポーネントのラッピング

これまでのところ、効果はかなりありましたが、インポートするためにたくさんのものを使用するたびに、それは私を悩ませました.


簡単にまとめましょう。

 import { useRef, useEffect } from 'react'; import * as echarts from 'echarts/core'; import { BarChart, LineChart, PieChart } from 'echarts/charts'; import { DataZoomComponent, GridComponent, LegendComponent, TitleComponent, ToolboxComponent, TooltipComponent, } from 'echarts/components'; import { SVGRenderer, SvgChart as _SvgChart, SkiaChart as _SkiaChart, } from '@wuba/react-native-echarts'; import { Dimensions } from 'react-native'; // Register the required components echarts.use([ DataZoomComponent, SVGRenderer, BarChart, GridComponent, LegendComponent, ToolboxComponent, TooltipComponent, TitleComponent, PieChart, LineChart, ]); // Default width and height of the chart const CHART_WIDTH = Dimensions.get('screen').width; // Default with the phone screen 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, 'light', { renderer: 'svg', 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} />; // Just export these two guys export { SkiaChart, SvgChart };

ステップ 8. 複数のグラフを使用する

ラップしたら、複数のチャートを含むページを作成して、どのように機能するかを見てみましょう。折れ線グラフ、棒グラフ、円グラフを含む「ECデータ分析」のページです。以下はsvgモードで書いた主なコードです。詳細なコードはここをクリックしてください。


 import { SkiaChart } from '../../components/Chart'; import { ScrollView, Text, View } from 'react-native'; import { StatusBar } from 'expo-status-bar'; import { useCallback, useEffect, useState } from 'react'; import { defaultActual, lineOption, salesStatus, salesVolume, userAnaly, getLineData, } from './contants'; import styles from './styles'; // Turn on chart loading const showChartLoading = (chart) => chart.showLoading('default', { maskColor: '#305d9e', }); // Close chart loading const hideChartLoading = (chart) => chart.hideLoading(); export default () => { const [actual, setActual] = useState(defaultActual); // Recording real-time data useEffect(() => { // Assuming a recurring request for data 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); // Simulation of data requests setTimeout(() => { myChart.setOption({ series: getLineData, }); hideChartLoading(myChart); }, 1000); }, []); const onInitUserChart = useCallback((myChart) => { // Simulate data request, similar to onInitLineChart }, []); const onInitSaleChart = useCallback((myChart) => { // Simulate data request, similar to onInitLineChart }, []); const onInitStatusChart = useCallback((myChart) => { // Simulate data request, similar to onInitLineChart }, []); const chartList = [ ['订单走势', lineOption, onInitLineChart], ['用户统计', userAnaly, onInitUserChart], ['各品类销售统计', salesVolume, onInitSaleChart], ['订单状态统计', salesStatus, onInitStatusChart], ]; return ( <ScrollView style={styles.index}> <StatusBar style='light' /> <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> ); };


バンドルをリロードして結果を確認する

iOS

アンドロイド

写真

写真

レンダリング後、iOS での操作は非常にスムーズですが、Android での操作は時折ラグが感じられます (私の携帯電話の調子が悪いからではありませんよね?...)。


Skiaモードを再試行中...

写真

うーん、できるのですが、中国語がちゃんと表示できなかったり、Android の中国語が表示されなかったり、iOS はコードがめちゃくちゃだったりするようです。


ドキュメントを読んだところ、現在skiaはAndroid側で中国語をサポートしていませんが、


iOS で中国語を表示するには、フォントを「PingFang SC」に設定します。次に例を示します。

 const option = { title: { text: '我是中文', textStyle: { fontFamily: 'PingFang SC', // setting the font type }, }, };

しかし、中国語を表示するすべての場所でフォントを設定する必要があります...それか最初にSvgを使用するか、私は怠け者です。

まとめ

しばらく使用した後、次のようにまとめました。

  • サポートに関しては、@wuba/react-native-echarts は、まだサポートされていない GL シリーズとマップ チャートを除くすべてのタイプのチャートをサポートしており、日常業務には非常に十分です。 echarts でさまざまなチャートを実装するコードは、taro-playgroundにあります。

  • インタラクション、iOSは非常に滑らか、Androidはたまにフレーム落ちするケースがあります。

  • パフォーマンス: パフォーマンスは、他のソリューションよりも優れていると公式に報告されています。

    • 試してみたところ、データ量が極端に多い場合は問題ありませんが、データ量が多すぎる場合(大量のデータのヒートマップを描画する場合など)、レンダリング速度が大幅に低下しました。公式が最適化するのを待っているポイント。
    • また、ページ内のチャートが多い場合、実機でのデバッグ時に読み込み速度が遅くなるため、シミュレーターを先に使用することをお勧めします。
  • 中国語のサポート、Svg モードは中国語をサポートしますが、Skia モードはまだ使用できません。


上記は個人的な見解ですので、質問やコメントは以下からどうぞ!