Коли потрібна кастомна візуалізація на Visx?
Типовий запит від клієнта: відобразити динаміку курсу акцій за останній рік з можливістю наближення та тултипами. Recharts не справляється з нестандартною анімацією, Chart.js гальмує на 50 000 точках. Потрібна кастомна візуалізація на Visx — бібліотеці Airbnb, що поєднує гнучкість D3.js з парадигмою React. Visx — це інструмент для React-візуалізацій, який поєднує D3.js із зручністю React-компонентів, дозволяючи створювати кастомні графіки та інтерактивні діаграми. Ми використовуємо його в проектах з датасетами до 100 000 записів, забезпечуючи плавну анімацію та миттєве оновлення. Наша компанія має понад 5 років досвіду в розробці кастомних візуалізацій та реалізувала більше 50 проектів на Visx.
Які проблеми вирішує Visx?
Обмежена кастомізація готових бібліотек
Recharts пропонує безліч конфігурацій, але будь-яке відхилення від шаблону перетворюється на хак з перевизначенням пропсів. Visx дає повний контроль над SVG-примітивами: ви керуєте кожним елементом, шкалами та переходами.
Продуктивність на великих обсягах даних
D3-рендеринг через React-життєвий цикл може викликати зайві ререндери. Visx оптимізує це за рахунок чистих компонентів та мемоізації. Visx показує продуктивність у 2-3 рази вище, ніж Chart.js, при роботі з датасетами понад 10 000 точок. На практиці ми досягаємо 60 FPS на датасетах з 10 000 точок.
Інтеграція з React-додатком
Visx-компоненти — це звичайні React-компоненти, які легко вбудовуються в будь-яку архітектуру: Next.js, CRA, Vite. Не потрібно підключати окремий рендерер або контекст.
Як Visx вирішує задачу кастомізації?
Visx пропонує низькорівневі примітиви: scaleTime, scaleLinear, LinePath, AreaClosed, AxisLeft, AxisBottom. З них збирається будь-який графік без огляду на шаблони. Для інтерактиву — хук useTooltip та події миші. Весь код — TypeScript з типізацією даних. Використання SVG-примітивів дозволяє гнучко керувати рендерингом, а шкали (scaleTime, scaleLinear) забезпечують точне масштабування даних. Мемоізація та чистота компонентів мінімізують перемальовування.
Візьмемо типову задачу: лінійний графік з тултипом та зоною заливки. Приклад реалізації на Visx (фрагмент):
import { scaleTime, scaleLinear } from '@visx/scale'; import { LinePath, AreaClosed } from '@visx/shape'; import { AxisLeft, AxisBottom } from '@visx/axis'; import { GridRows, GridColumns } from '@visx/grid'; import { useTooltip, TooltipWithBounds, defaultStyles } from '@visx/tooltip'; import { localPoint } from '@visx/event'; import { bisector } from 'd3-array'; import { curveMonotoneX } from 'd3-shape'; interface DataPoint { date: Date; value: number; } const bisectDate = bisector<DataPoint, Date>(d => d.date).left; function CustomLineChart({ data, width, height, margin = { top: 20, right: 20, bottom: 40, left: 60 } }: { data: DataPoint[]; width: number; height: number; margin?: { top: number; right: number; bottom: number; left: number }; }) { const innerWidth = width - margin.left - margin.right; const innerHeight = height - margin.top - margin.bottom; const xScale = scaleTime({ range: [0, innerWidth], domain: [ Math.min(...data.map(d => d.date.getTime())), Math.max(...data.map(d => d.date.getTime())) ] }); const yScale = scaleLinear({ range: [innerHeight, 0], domain: [0, Math.max(...data.map(d => d.value)) * 1.1], nice: true }); const { tooltipData, tooltipLeft, tooltipTop, showTooltip, hideTooltip } = useTooltip<DataPoint>(); const handleTooltip = (event: React.MouseEvent<SVGRectElement>) => { const { x } = localPoint(event) || { x: 0 }; const x0 = xScale.invert(x - margin.left); const index = bisectDate(data, x0, 1); const d0 = data[index - 1]; const d1 = data[index]; const d = !d1 || Math.abs(x0.getTime() - d0.date.getTime()) < Math.abs(x0.getTime() - d1.date.getTime()) ? d0 : d1; showTooltip({ tooltipData: d, tooltipLeft: xScale(d.date) + margin.left, tooltipTop: yScale(d.value) + margin.top }); }; return ( <div style={{ position: 'relative' }}> <svg width={width} height={height}> <g transform={`translate(${margin.left}, ${margin.top})`}> <GridRows scale={yScale} width={innerWidth} stroke="#f0f0f0" /> <GridColumns scale={xScale} height={innerHeight} stroke="#f0f0f0" /> <defs> <linearGradient id="areaGradient" x1="0" y1="0" x2="0" y2="1"> <stop offset="0%" stopColor="#3b82f6" stopOpacity={0.3} /> <stop offset="100%" stopColor="#3b82f6" stopOpacity={0} /> </linearGradient> </defs> <AreaClosed data={data} x={d => xScale(d.date)} y={d => yScale(d.value)} yScale={yScale} fill="url(#areaGradient)" curve={curveMonotoneX} /> <LinePath data={data} x={d => xScale(d.date)} y={d => yScale(d.value)} stroke="#3b82f6" strokeWidth={2} curve={curveMonotoneX} /> <AxisLeft scale={yScale} tickFormat={v => `${(v as number / 1000).toFixed(0)}k`} /> <AxisBottom top={innerHeight} scale={xScale} tickFormat={d => format(d as Date, 'dd MMM')} /> <rect width={innerWidth} height={innerHeight} fill="transparent" onMouseMove={handleTooltip} onMouseLeave={hideTooltip} /> {tooltipData && ( <g> <line x1={tooltipLeft! - margin.left} x2={tooltipLeft! - margin.left} y1={0} y2={innerHeight} stroke="#3b82f6" strokeDasharray="4,4" strokeWidth={1} /> <circle cx={tooltipLeft! - margin.left} cy={tooltipTop! - margin.top} r={5} fill="#3b82f6" stroke="white" strokeWidth={2} /> </g> )} </g> </svg> {tooltipData && ( <TooltipWithBounds top={tooltipTop} left={tooltipLeft} style={{ ...defaultStyles, background: '#1e293b', color: 'white' }} > <div> <strong>{format(tooltipData.date, 'dd.MM.yyyy')}</strong> <br /> {tooltipData.value.toLocaleString('uk')} ₴ </div> </TooltipWithBounds> )} </div> ); } ParentSize для адаптивності
import { ParentSize } from '@visx/responsive'; function ResponsiveChart({ data }) { return ( <ParentSize> {({ width, height }) => ( <CustomLineChart data={data} width={width} height={height || 300} /> )} </ParentSize> ); } Чому Visx, а не Chart.js?
Visx кращий за Chart.js у ситуаціях, де потрібна нестандартна форма графіка або складні інтерактивні сценарії. Chart.js простіший у налаштуванні та швидший для простих діаграм, але його архітектура гірше масштабується під кастомні завдання. Visx дає повний доступ до SVG, що дозволяє реалізувати будь-яку візуалізацію. Наші клієнти економлять до 40% часу на розробці складних дашбордів за рахунок використання Visx. Середня вартість одного типу візуалізації — 1200 $, комплекту з 3-4 типів — 3000-4500 $.
Порівняння Visx та Recharts
| Критерій | Visx | Recharts |
|---|---|---|
| Рівень контролю | Повний (SVG-примітиви) | Середній (конфігурація пропсів) |
| Кастомізація | Безмежна | Обмежена шаблонами |
| Продуктивність | Висока (ручне управління) | Середня (автоматичні ререндери) |
| Час розробки | 3-5 днів на тип | 1-2 дні на тип |
| Поріг входу | Середній (потрібно знати d3) | Низький (React-only) |
Типові помилки при роботі з Visx
- Пропуск мемоізації шкал. Шкали потрібно створювати всередині useMemo або поза компонентом, інакше кожен ререндер буде перестворювати їх, що веде до втрати продуктивності.
- Ігнорування ParentSize. Без адаптивного контейнера графік не реагуватиме на зміну розмірів вікна, що ламає UX на мобільних пристроях.
- Некоректна обробка країв даних. Якщо дані містять NaN або null, Visx може викинути помилку. Завжди фільтруйте дані перед передачею в компоненти.
- Забули про accessibility. SVG-графіка повинна бути доступна для скрінрідерів: додавайте role="img" та aria-label.
Як створити кастомний графік з нуля?
- Визначте шкали —
scaleTimeдля часу,scaleLinearдля значень. - Опишіть геометрію —
LinePathдля лінії,AreaClosedдля заливки. - Додайте осі —
AxisLeftтаAxisBottom. - Реалізуйте тултип — використовуйте хук
useTooltipта події миші. - Обгорніть в адаптивний контейнер —
ParentSizeдля автоматичного ресайзу.
Процес роботи та терміни
| Етап | Тривалість |
|---|---|
| Аналітика та збір вимог | 0.5–1 день |
| Прототипування MVP | 1–2 дні |
| Розробка фінальної версії | 3–5 днів на тип |
| QA та оптимізація продуктивності | 1–2 дні |
| Деплой та інтеграція | 0.5–1 день |
Повний цикл розробки одного типу візуалізації займає від 3 до 5 днів. Комплект з 3–4 різних типів — від 1.5 до 2 тижнів. Середня вартість одного типу — 1200 $, комплекту — 3000-4500 $. Вартість робіт може змінюватись в залежності від складності інтерактиву та обсягу даних. Ми гарантуємо якість коду та документацію, а наш досвід роботи з Visx перевищує 4 роки.
Що входить в роботу?
Ми виконуємо розробку візуалізації даних на Visx під ключ:
- аналіз вимог та проектування макету;
- написання коду з нуля на React + TypeScript;
- тестування на реальних даних (до 100 000 записів);
- адаптація під мобільні екрани та retina-дисплеї;
- документація в README та інлайн-коментарях;
- передача доступів до репозиторію та деплою;
- навчання вашої команди роботі з Visx (вебінар 1 година).
Зв'яжіться з нами для обговорення вашого завдання. Отримайте консультацію з кастомної візуалізації.







