import React, { useEffect, useRef, useMemo } from 'react';
import { Chart as ChartJS, CategoryScale, LinearScale, PointElement, BarElement, Title, Tooltip, Legend, Filler,} from 'chart.js';
import { Bar } from 'react-chartjs-2';
import { useVeltClient, useCommentAnnotations, useCommentModeState, VeltCommentPin } from '@veltdev/react';
// Register the necessary Chart.js components
ChartJS.register(CategoryScale, LinearScale, PointElement, BarElement, Title, Tooltip, Legend, Filler);
// Define the data for the chart
const scores = [6, 5, 5, 5, 3, 4, 6, 4, 5];
const labels = [100, 200, 300, 400, 500, 600, 700];
// Set the options for the chart
const options: any = {
// your chart options
};
const BarChart = () => {
const chartId = 'dataAnalyticsChart'; // Unique ID for the chart
const chartRef = useRef(null); // Reference to the chart instance
const { client } = useVeltClient(); // Get Velt client
const commentModeState = useCommentModeState(); // Get Velt comment mode state
const commentAnnotations = useCommentAnnotations(); // Get Velt comment annotations
const [chartCommentAnnotations, setChartCommentAnnotations] = React.useState([]); // State for chart comments
// Update chart comments when annotations change
useEffect(() => {
// Filter comments for the current chart, using unique chart ID
const chartCommentAnnotations = commentAnnotations?.filter((comment) => comment.context?.chartId === chartId);
setChartCommentAnnotations(chartCommentAnnotations as any || []);
}, [commentAnnotations]);
// Handle chart clicks to find nearest data point and add a comment
const handleChartClick = (event: any) => {
const chart: any = chartRef.current;
if (chart) {
// Get the nearest element to the click event
const elements = chart.getElementsAtEventForMode(event.nativeEvent, 'nearest', { intersect: true }, false);
if (elements.length > 0) {
const element = elements[0];
const datasetIndex = element.datasetIndex;
const index = element.index;
const dataset = chart.data.datasets[datasetIndex];
const xValue = chart.data.labels[index];
const yValue = dataset.data[index];
const context = { seriesId: dataset.label, xValue, yValue, chartId };
addManualComment(context); // Add a comment at the nearest data point with the context data
}
}
};
// Add a manual comment to the chart
const addManualComment = (context: any) => {
try {
if (client && commentModeState) {
const commentElement = client.getCommentElement();
commentElement.addManualComment({ context }); // Add a Velt comment
}
} catch (error) {
console.error('Error adding manual comment', error);
}
};
// Find the exact point on the chart to place a comment pin
const findPoint = (seriesId: any, xValue: any, yValue: any) => {
const chart: any = chartRef.current;
if (chart) {
const dataset = chart.data.datasets.find((dataset: any) => dataset.label === seriesId);
const index = chart.data.labels.indexOf(xValue);
if (dataset && index !== -1) {
const yValueInDataset = dataset.data[index];
if (yValueInDataset === yValue) {
return { x: chart.scales.x.getPixelForValue(index), y: chart.scales.y.getPixelForValue(yValue) }; // Set the x, y position for the comment pin
}
}
}
return null;
};
// Show the comment pin on the chart at the specified point
const showCommentPin = (commentAnnotation: any) => {
const context = commentAnnotation.context || {};
const point = findPoint(context.seriesId, context.xValue, context.yValue);
if (point) {
const { x, y } = point;
return (
<div
key={commentAnnotation.annotationId}
style={{
left: `${x}px`,
top: `${y}px`,
position: 'absolute',
transform: 'translate(0%, -100%)',
zIndex: 1000,
}}
>
<VeltCommentPin annotationId={commentAnnotation.annotationId} /> {/* Velt comment pin component */}
</div>
);
}
return null;
};
// Memoize the chart data
const data = useMemo(() => {
return {
datasets: [
{
label: 'Mis datos',
tension: 0.3,
data: scores,
borderColor: 'rgb(75, 192, 192)',
backgroundColor: 'rgba(75, 192, 192, 0.3)',
},
],
labels,
};
}, []);
return (
<div className="dashlet-card">
<div className="dashlet-card-header">Bar Chart With Comments</div>
{/* Keep the parent div as relative, as comment pin will be placed with absolute position */}
{/* Set "data-velt-manual-comment-container" to true, so that comment pin will know which div to consider while positioning */}
<div style={{ position: 'relative' }} onClick={handleChartClick} data-velt-manual-comment-container="true">
<Bar data={data} options={options} ref={chartRef} /> {/* Render the Bar chart */}
{chartCommentAnnotations.map((comment, index) => showCommentPin(comment))} {/* Show all comment pins */}
</div>
</div>
);
};
export default BarChart;