Components
Loading preview...
here is annotation component
npx shadcn@latest add https://21st.dev/r/airbnb/annotation// DemoOne.tsx
import React, { useState, useEffect, useMemo } from 'react';
import { Component, DataPoint } from '@/components/ui/annotation';
import { Annotation } from '@visx/annotation';
import { scaleTime, scaleLinear } from '@visx/scale';
import { extent } from 'd3-array';
import { cn } from '@/lib/utils';
const mockStockData: DataPoint[] = [
{ date: '2023-01-01', value: 100 },
{ date: '2023-01-05', value: 110 },
{ date: '2023-01-10', value: 105 },
{ date: '2023-01-15', value: 120 },
{ date: '2023-01-20', value: 115 },
{ date: '2023-01-25', value: 130 },
{ date: '2023-01-30', value: 125 },
{ date: '2023-02-05', value: 135 },
{ date: '2023-02-10', value: 140 },
{ date: '2023-02-15', value: 138 },
{ date: '2023-02-20', value: 150 },
];
const getDate = (d: DataPoint): Date => new Date(d.date);
const getStockValue = (d: DataPoint): number => d.value;
const DemoOne = () => {
const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
useEffect(() => {
const updateDimensions = () => {
setDimensions({
width: window.innerWidth,
height: window.innerHeight,
});
};
updateDimensions();
window.addEventListener('resize', updateDimensions);
return () => window.removeEventListener('resize', updateDimensions);
}, []);
const chartWidth = dimensions.width;
const chartHeight = dimensions.height;
const margin = { top: 20, right: 30, bottom: 50, left: 50 };
const innerWidth = chartWidth - margin.left - margin.right;
const innerHeight = chartHeight - margin.top - margin.bottom;
const xScale = useMemo(() => scaleTime<number>({
domain: extent(mockStockData, getDate) as [Date, Date],
range: [0, innerWidth],
}), [innerWidth]);
const yScale = useMemo(() => scaleLinear<number>({
domain: [
Math.min(...mockStockData.map(getStockValue)) * 0.9,
Math.max(...mockStockData.map(getStockValue)) * 1.1,
],
range: [innerHeight, 0],
}), [innerHeight]);
const defaultAnnotatedDatum = mockStockData[5];
const initialAnnotationX = xScale(getDate(defaultAnnotatedDatum)) ?? 0;
const initialAnnotationY = yScale(getStockValue(defaultAnnotatedDatum)) ?? 0;
const [annotationPosition, setAnnotationPosition] = useState({
x: initialAnnotationX,
y: initialAnnotationY,
dx: 50,
dy: -50,
});
useEffect(() => {
const currentX = xScale(getDate(defaultAnnotatedDatum)) ?? 0;
const currentY = yScale(getStockValue(defaultAnnotatedDatum)) ?? 0;
setAnnotationPosition((prev) => ({
x: currentX,
y: currentY,
dx: prev.dx,
dy: prev.dy,
}));
}, [xScale, yScale, defaultAnnotatedDatum]);
if (chartWidth === 0 || chartHeight === 0) {
return (
<div className={cn("flex w-screen h-screen justify-center items-center bg-gray-900 text-white")}>
Загрузка...
</div>
);
}
return (
<div className={cn("w-screen h-screen overflow-hidden bg-gray-800 flex justify-center items-center")}>
<svg width={chartWidth} height={chartHeight}>
<g transform={`translate(${margin.left}, ${margin.top})`}>
<Component
width={innerWidth}
height={innerHeight}
data={mockStockData}
xScale={xScale}
yScale={yScale}
getDate={getDate}
getStockValue={getStockValue}
AnnotationComponent={Annotation}
annotationPosition={annotationPosition}
onAnnotationPositionChange={setAnnotationPosition}
connectorType="elbow"
labelType="html"
subjectType="circle"
subtitle="The stock reached its highest value today."
labelWidth={160}
approxTooltipHeight={70}
editLabelPosition={true}
editSubjectPosition={true}
showAnchorLine={true}
horizontalAnchor="start"
verticalAnchor="end"
/>
</g>
</svg>
</div>
);
};
export { DemoOne };