Bienvenido, soy Luis y hoy les traigo un nuevo tutorial.
Cómo manejar gráficos de amCharts
de manera eficiente
amCharts es una biblioteca de JavaScript para visualización de datos con soporte integrado para módulos TypeScript
y ES6
. También es totalmente compatible con Angular, Reaccionar, Vue.js. amCharts ofrece una amplia selección de tipos de gráficos, tal como se presentan aquí.
He estado usando amCharts durante meses y ahora conozco sus principales ventajas y desventajas. Cuando se usa para gráficos estáticos, es simplemente asombroso. ¿Qué pasa con los gráficos dinámicos?
Esto puede convertirse fácilmente el cuello de botella de una aplicación web, especialmente si hay muchos gráficos (dependiendo de este evento) en la misma página. ¡Aquí es donde memorización entra en juego!
Tenga en cuenta que el objetivo principal de este artículo no es mostrar cómo funciona amCharts ni qué es la memorización. Esta es la razón por la que Recomiendo encarecidamente leer esto .
Construyamos un componente React eficiente diseñado para envolver cualquier tipo de gráfico amCharts.
Construyendo el componente de gráfico
Nuestro componente genérico se puede definir de la siguiente manera:
function Chart(props) { const {idHtmlElement, onInitialize, ...remainingProps} = props; const [chart, setChart] = useState(undefined); const initializeChart = React.useMemo(() => { return () => { const chart = am4core.create(idHtmlElement, am4charts.XYChart); // ... customizing the chart return chart; } }, [] ) useEffect(() => { const chart = initializeChart(); // saving the chart reference in the component's state // since it might be useful setChart(chart); // passing the chart reference to the parent component onInitialize(chart); }, []); return ( <div id={idHtmlElement} {...remainingProps} /> ) } Chart.propTypes = { idHtmlElement: PropTypes.string.isRequired, onInitialize: PropTypes.func.isRequired } export default Chart;
La función am4core.create
devuelve la instancia de gráfico, que es lo que nos permite manipular el comportamiento del gráfico en sí. La creación del gráfico, es decir, su inicialización, debe ejecutarse solo la primera vez que se renderiza el componente.
De lo contrario, este componente se convertiría extremadamente ineficiente. Es por eso que envolvimos nuestra función de inicialización en llamar useMemo de vuelta.
char
, que se llama solo cuando el componente se invoca por primera vez. Cada vez que el componente vuelve a renderizar chart
. Se utilizará el valor en caché, evitando la sobrecarga de inicialización.Si queremos que nuestro gráfico sea manipulado sin que se vuelva a crear cada vez, debemos exponer su referencia al componente principal. Por esta razón, agregamos el onInitialization
apuntalar.
Gracias a eso el padre puede cambiar la apariencia, los datos y el comportamiento del gráfico operando directamente en su instancia.
Las principales fortalezas de este enfoque son dos:
- Evitando la duplicación de código creando un componente por tipo de gráfico.
- Permitiendo que el componente padre interactuar directamente con el gráfico lo que sea y cuando quiera.
ChartComponent
en acción
Digamos que queremos crear una evolución temporal. Gráfico de linea, como este:
amCharts
.Los datos a visualizar serán recuperados de una llamada AJAX, cuyo resultado depende del lapso de tiempo seleccionado por el usuario. En primer lugar, definamos el TemporalEvolutionChart
componente:
function TemporalEvolutionChart(props) { const {idHtmlElement, onInitialize, ...remainingProps} = props; const [chart, setChart] = useState(undefined); const initializeChart = React.useMemo(() => { return () => { const chart = am4core.create(idHtmlElement, am4charts.XYChart); // defining the temporal evolution line chart const categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis()); categoryAxis.dataFields.category = "time"; const valueAxis = chart.yAxes.push(new am4charts.ValueAxis()); const lineSeries = chart.series.push(new am4charts.LineSeries()); lineSeries.dataFields.valueY = "value"; lineSeries.dataFields.categoryX = "time"; chart.scrollbarX = new am4core.Scrollbar(); chart.scrollbarX.parent = chart.bottomAxesContainer; chart.legend = new am4charts.Legend(); return chart; } }, [] ) useEffect(() => { const chart = initializeChart(); // saving the chart reference in the component's state // since it might be useful setChart(chart); // passing the chart reference to the parent component onInitialize(chart); }, []); return ( <div id={idHtmlElement} {...remainingProps} /> ) } TemporalEvolutionChart.propTypes = { idHtmlElement: PropTypes.string.isRequired, onInitialize: PropTypes.func.isRequired } export default TemporalEvolutionChart;
El componente padre es el encargado de realizar la llamada para recuperar los datos que se mostrarán en el gráfico y pasarlos.
Esto se hace asignando el resultado de la llamada AJAX a la propiedad data
de la instancia de gráfico. El gráfico amCharts
representará automáticamente los nuevos datos.
function ParentComponent(props) { // ... const [timeSpan, setTimeSpan] = useState(undefined) // to store the chart reference const [temporalEvolutionChart, setTemporalEvolutionChart] = useState(undefined) // ... useEffect(() => { // if temporalEvolutionChart and timeSpan are defined if (temporalEvolutionChart && timeSpan) { // using the API definition layer described here: // https://codeburst.io/avoiding-code-duplication-by-adding-an-api-requests-definition-layer-in-javascript-6e5d7b409896 DataAPI .getTemporalEvolutionChartData(timeSpan) .then((response) => { // automatically updating temporalEvolutionChart's data temporalEvolutionChart.data = response.data } ) } }, [temporalEvolutionChart, timeSpan]); return ( // ... <> <TimeSpanSelector value={timeSpan} onChange={(timeSpan) => { setTimeSpan(timeSpan) }} /> <TemporalEvolutionChart idHtmlElement={"temporalEvolutionChart1"} onInitialize={(chart) => { // retrieving the chart reference setTemporalEvolutionChart(chart) }} /> </> // ... ) } export default ParentComponent
Tan pronto como un usuario cambia el intervalo de tiempo de interés, se realiza una llamada AJAX (gracias a la capa de definición de API introducida aquí) y el gráfico se actualiza en consecuencia. Esto, de una manera muy eficiente sin inicializar el gráfico cada vez.
amCharts
con React
. Inicializar un gráfico de amCharts
es una operación que requiere mucho tiempo, que debe ejecutarse solo cuando sea absolutamente necesario.
Este enfoque es un gran ejemplo de cómo ahorrar recursos y evitar que los usuarios se sientan frustrados debido a una página web muy lenta.
Gracias por leer. Ojalá haya cubierto tus espectativas.
Añadir comentario