import { Utils } from 'arm-common'; import p from 'prop-types'; import React, { useLayoutEffect, useMemo, useState } from 'react'; import { ChartContainer, useAm5, useAm5Colors, getRoot } from '../Am5.jsx'; import { AutoSize } from 'arm-core-layouts'; const classNamePrefix = 'armu_ai_chatbot-bar-chart'; export default function BarChart(props) { const { id, xAxis, yAxis, series, data } = props; const [chartId] = useState(id || Utils.uuid(classNamePrefix)); const am5 = useAm5(); const am5Colors = useAm5Colors(); const allValues = useMemo(() => { if (data?.length) { if (series?.length) { const values = []; for (let item of data) { for (let serie of series) { if (!isNaN(item[serie.yAxis])) { values.push(item[serie.yAxis]); } } } return values; } else { return data.map(d => d[yAxis]); } } return []; }, [data, series, yAxis]); const minValue = Math.min(...allValues); useLayoutEffect(() => { if (am5 && data) { const root = getRoot(chartId); const chart = root.container.children.push( am5xy.XYChart.new(root, { layout: root.verticalLayout }) ); const yAxisAm5 = chart.yAxes.push( am5xy.CategoryAxis.new(root, { categoryField: xAxis, renderer: am5xy.AxisRendererY.new(root, { inversed: true, cellStartLocation: 0.1, cellEndLocation: 0.9 }) }) ); yAxisAm5.data.setAll(data); const xAxisAm5 = chart.xAxes.push( am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererX.new(root, { strokeOpacity: 0.1 }), min: minValue < 0 ? minValue : 0, }) ); chart.set("colors", am5.ColorSet.new(root, { colors: am5Colors })); if (series?.length){ const legend = chart.children.push(am5.Legend.new(root, { centerX: am5.p50, x: am5.p50, })); series.forEach(addSeries.bind({ root, chart, xAxisAm5, yAxisAm5, xAxis, data })); legend.data.setAll(chart.series.values); } else if (yAxis){ addSeries.call({ root, chart, xAxisAm5, yAxisAm5, xAxis, data }, { yAxis }); } const cursor = chart.set("cursor", am5xy.XYCursor.new(root, { behavior: "zoomY" })); cursor.lineY.set("forceHidden", true); cursor.lineX.set("forceHidden", true); } }, [am5, allValues]); const height = useMemo(() => calcHeight(data, series), [data, series]); return ( ); } BarChart.defaultProps = { id: '', xAxis: '', yAxis: '', series: [], data: null } BarChart.propTypes = { id: p.string, xAxis: p.string.isRequired, yAxis: p.string, series: p.arrayOf(p.shape({ name: p.string, yAxis: p.string })), data: p.arrayOf(p.object).isRequired } function addSeries(seriesConfig) { const { root, chart, xAxisAm5, yAxisAm5, xAxis, data } = this; const { name, yAxis } = seriesConfig; const series = chart.series.push( am5xy.ColumnSeries.new(root, { name, minBulletDistance: 10, xAxis: xAxisAm5, yAxis: yAxisAm5, valueXField: yAxis, categoryYField: xAxis, sequencedInterpolation: true, tooltip: am5.Tooltip.new(root, { pointerOrientation: "horizontal", labelText: "[bold]{name}[/]\n{categoryY}: {valueX}" }) }) ); series.columns.template.setAll({ height: am5.p100, strokeOpacity: 0 }); series.bullets.push(function () { return am5.Bullet.new(root, { locationX: 1, locationY: 0.5, sprite: am5.Label.new(root, { centerY: am5.p50, text: "{valueX}", populateText: true }) }); }); series.bullets.push(function () { return am5.Bullet.new(root, { locationX: 1, locationY: 0.5, sprite: am5.Label.new(root, { centerX: am5.p100, centerY: am5.p50, text: "{name}", fill: am5.color(0xffffff), populateText: true }) }); }); series.data.setAll(data); series.columns.template.setAll({ cornerRadiusBR: 5, cornerRadiusTR: 5, strokeOpacity: 0 }); series.appear(); } function calcHeight(data, series) { const lineHeight = AutoSize.convertRemToPixels(3); const barHeight = AutoSize.convertRemToPixels(4); return (lineHeight * (data.length + 1)) + (barHeight * ((series?.length || 0) + 1)) + AutoSize.convertRemToPixels(5); }