paint-brush
La meilleure façon de faire React Native Charting en 2023par@zhiqingchen
4,000 lectures
4,000 lectures

La meilleure façon de faire React Native Charting en 2023

par zhiqingchen13m2023/03/30
Read on Terminal Reader

Trop long; Pour lire

La bibliothèque de graphiques la plus utilisée pour écrire les exigences relatives aux graphiques est **echarts**. Les performances des echarts sur le site Web sont assez matures et la solution officielle est fournie pour le côté applet, mais il n'y a pas de support correspondant dans RN. Sur le marché, la plupart des recherches sont toujours basées sur l'essence de la mise en œuvre de la vue Web, et je préfère le programme basé sur RN.
featured image - La meilleure façon de faire React Native Charting en 2023
zhiqingchen HackerNoon profile picture
0-item
1-item

La bibliothèque de graphiques la plus utilisée pour écrire des exigences liées aux graphiques est echarts .


Les performances des echarts sur le site Web sont assez matures et la solution officielle est fournie pour le côté applet, mais il n'y a pas de support correspondant dans RN. Sur le marché, la plupart des recherches sont toujours basées sur l'essence de la mise en œuvre de la vue Web, et je préfère le programme basé sur RN. Après tout, l'expérience native sera meilleure que le Web.


Plus tard, j'ai trouvé @wuba/react-native-echarts pour répondre à mes besoins, alors essayez-le ; les résultats ne sont pas mauvais. Pour les personnes intéressées par le principe de mise en œuvre, cliquez ici

Conseils

  • Si vous avez déjà un package APP, vous pouvez ignorer le processus d'emballage précédent et commencer directement à partir de l'étape 4.
  • Le code complet de l'essai est sur GitHub à : https://github.com/iambool/TestApp

Les étapes pour l'utiliser sont les suivantes

Étape 1. Configuration de l'environnement de développement

Il s'agit du processus de création d'un environnement de développement RN local qui est déjà disponible sur Internet, je ne le reviendrai donc pas. Vous pouvez le rechercher sur Google :)

Étape 2. Créer un projet RN

Comme il s'agissait d'un essai, j'ai utilisé l'expo pour initialiser un nouveau projet rn appelé TestApp.

 npx create-expo-app TestApp 

créer TestApp

Étape 3. Créer une application sur des appareils mobiles

Générez des packages d'applications iOS et Android avec une ligne de commande.


iOS est recommandé d'utiliser l'émulateur (pas besoin de faire correspondre le certificat). Alors que sur Android, j'étais connecté à la vraie machine.


 yarn android yarn ios


Après avoir généré le package, l'application comme celle ci-dessous est déjà installée sur le téléphone, ce qui signifie qu'elle a réussi.

image

Étape 4. Installer les dépendances associées

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

Remarque : si vous installez dans un projet existant, vous devez créer un nouveau package une fois l'installation terminée, sinon l'absence de dépendances natives signalera une erreur.

Étape 5. Essayez le modèle Skia

@wuba/react-native-echarts prend en charge deux modes de rendu (Skia et Svg) , essayez d'abord un graphique simple avec Skia.


Il est divisé en ces petites étapes:


  • Introduisez des echarts, des composants de graphique et d'autres dépendances.
  • Enregistrement des composants du graphique.
  • Créez une instance de graphique et définissez une option.
  • Destruction synchronisée des instances de graphique lorsque la page est détruite.


Le code spécifique est le suivant :

 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> ); };


Après avoir écrit le code, secoué le téléphone et rechargé le package groupé, une erreur a été signalée :

ERREUR Invariant Violation : requireNativeComponent : "SkiaDomView" n'a pas été trouvé dans UIManager.


Je l'ai googlé et il dit qu'il nécessite une rétrogradation de version . Cela devrait correspondre à la version expo, il y aura une invite similaire lors de l'installation de la dépendance, installez la version invitée et tout ira bien.

avertissement

J'ai donc suivi les instructions et fait un downgrade de version :

 @shopify/[email protected] [email protected]

Il s'est chargé après la reconstruction de l'application, ce qui était bien. (mais Android couvre le point, il semble que la largeur de l'écran devrait être adaptative.)

iOS

Android

iOS

Android

Étape 6. Essayez le modèle Svg

Écrivez un graphique à barres de tri dynamique plus complexe avec le mode Svg et comparez Svg et Skia. Le code complet est ici

 // ...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> ); };


Je ne vois pas la différence entre ces deux modes de mes propres yeux.

iOS

Android

image

image

Étape 7. Envelopper les composants du graphique

Jusqu'ici l'effet était plutôt bon, mais à chaque fois que j'utilisais un tas de trucs à importer, ça me gênait.


Résumons simplement :

 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 };

Étape 8. Utiliser plusieurs graphiques

Une fois qu'il est emballé, écrivons une page avec plusieurs graphiques et voyons comment cela fonctionne. Voici une page pour "l'analyse des données de commerce électronique", comprenant un graphique linéaire, un graphique à barres et un graphique à secteurs. Vous trouverez ci-dessous le code principal écrit en mode svg, cliquez ici pour le code détaillé.


 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> ); };


Rechargez le bundle et voyez le résultat

iOS

Android

image

image

Après le rendu, l'interaction sur iOS est très fluide, tandis que l'interaction sur Android semble parfois lag (pas parce que mon téléphone est trop mauvais, non ?...)


Essayer à nouveau le mode Skia…

image

Eh bien, même si c'est possible, il semble que le chinois ne puisse pas être affiché correctement, le chinois Android ne s'affiche pas et iOS est un gâchis de code.


Après avoir lu la documentation, skia ne prend actuellement pas en charge le chinois du côté Android,


Nous pouvons afficher le chinois sur iOS en définissant la police sur "PingFang SC", par exemple :

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

Mais chaque endroit qui affiche le chinois doit définir la police ... cela ou utiliser Svg en premier, je suis paresseux.

Résumé

Après l'avoir utilisé pendant un certain temps, j'ai résumé ce qui suit:

  • En termes de support, @wuba/react-native-echarts prend en charge tous les types de graphiques, à l'exception des séries GL et des graphiques cartographiques qui ne sont pas encore pris en charge, ce qui est largement suffisant pour les activités quotidiennes. Le code pour implémenter les différents graphiques dans echarts se trouve dans taro-playground .

  • Interaction, iOS est très fluide, Android parfois il y a des cas de chutes de trame.

  • Performances : les performances sont officiellement signalées comme meilleures que les autres solutions.

    • Je l'ai essayé, pas une très grande quantité de données n'aura aucun problème, mais lorsque la quantité de données est trop importante (comme dessiner une grande quantité de carte thermique de données), la vitesse de rendu a considérablement diminué, ce qui est un point d'attente pour l'officiel pour optimiser.
    • De plus, s'il y a beaucoup de graphiques sur la page, la vitesse de chargement sera lente lors du débogage sur la machine réelle, il est donc recommandé d'utiliser d'abord le simulateur.
  • Prise en charge du chinois, le mode Svg prend en charge le chinois, mais le mode Skia n'est pas encore disponible.


Ce qui précède n'est qu'un point de vue personnel, toutes les questions et commentaires sont les bienvenus ci-dessous !