GrChartArea
Берут, когда целое и вклад частей в него во времени.
Обзор
Когда брать
- целое и вклад частей в него во времени — выручка по каналам, трафик по
источникам, время по стадиям:
stackedкладёт каждую серию на сумму предыдущих; - один ряд, у которого важен объём — заливка до нуля читается как «сколько всего», а не «на каком уровне»;
- доли, меняющиеся во времени —
stacked: '100%'нормирует каждую позицию к единице, и видно перераспределение, а не рост; - ряды, которые обязаны просвечивать — при наложении без стека
fill: 'auto'даёт градиент, и нижний ряд остаётся виден.
Когда взять другое
| Нужно | Берите |
|---|---|
| Показать ход значения, объём не важен | GrChartLine |
| Сравнить величины по категориям | GrChartBar |
| Показать состав целого на один момент | GrChartPie |
| Сравнить форму профиля по нескольким осям | GrChartRadar |
| Тренд в ячейке таблицы | GrSparkline |
Категорий больше семи-восьми — стек перестаёт читаться: полосы становятся тоньше
подписи, и сравнить их глазом уже нельзя. Это признак того, что нужен
GrChartBar с группировкой либо меньше серий.
Примеры 5 у каждого — живое демо и его код
Выручка по каналам: верхний край — сумма
stackedкладёт каждый канал на сумму предыдущих, и верхний край читается как итог. План — линияreferences, а не серия, иinclude-references-in-domainоставляет её на экране. Канал, скрытый в легенде (v-model:hidden-series), выпадает и из стека, и из числа над графиком. Новый период показываетloading, пустой — слотempty, а слотtooltipназывает деньги в евро.Revenue in September€399k+4,7%Данные графика X Direct sales Partners Marketplace Apr 171 108 46 May 175 112 52 Jun 182 115 55 Jul 190 121 57 Aug 196 124 61 Sep 204 129 66 Plan €420k: 420 Сутки нагрузки сервера с приближением
1 440 точек на оси
time:decimateпрореживает нарисованный путь доmax-points, а курсор, клавиатура и скрытая таблица — с потолкомdata-table-max-rows— знают каждую минуту.zoom="both"принимает протяжку и колесо, аv-model:x-windowпозволяет «Whole day» сбросить окно. Зона перегрузки — опорная полоса;point-clickприкалывает момент к инциденту.api-eu-1 · CPU5 October, UTC · drag over the chart or scroll to zoom inДанные графика X CPU 5 окт. 2026 г., 00:00 12 5 окт. 2026 г., 00:14 20,5 5 окт. 2026 г., 00:36 9,7 5 окт. 2026 г., 00:39 18,7 5 окт. 2026 г., 00:58 9 5 окт. 2026 г., 01:01 18,1 5 окт. 2026 г., 01:23 7,6 5 окт. 2026 г., 01:26 16,7 5 окт. 2026 г., 01:48 6,5 5 окт. 2026 г., 01:51 15,6 5 окт. 2026 г., 02:13 5,6 5 окт. 2026 г., 02:16 14,7 5 окт. 2026 г., 02:35 5,9 5 окт. 2026 г., 02:41 14,2 5 окт. 2026 г., 03:00 5,5 5 окт. 2026 г., 03:03 14,7 5 окт. 2026 г., 03:25 5,5 5 окт. 2026 г., 03:28 14,7 5 окт. 2026 г., 03:50 5,7 5 окт. 2026 г., 03:53 14,9 5 окт. 2026 г., 04:12 6,9 5 окт. 2026 г., 04:18 15,4 5 окт. 2026 г., 04:37 7,6 5 окт. 2026 г., 04:43 16,2 5 окт. 2026 г., 05:02 8,6 5 окт. 2026 г., 05:05 18 5 окт. 2026 г., 05:27 9,9 5 окт. 2026 г., 05:30 19,2 5 окт. 2026 г., 05:49 12 5 окт. 2026 г., 05:55 20,7 5 окт. 2026 г., 06:14 13,6 5 окт. 2026 г., 06:20 22,4 5 окт. 2026 г., 06:39 15,5 5 окт. 2026 г., 06:45 24,3 5 окт. 2026 г., 07:04 17,5 5 окт. 2026 г., 07:07 26,9 5 окт. 2026 г., 07:26 20,2 5 окт. 2026 г., 07:32 29,1 5 окт. 2026 г., 07:51 22,4 5 окт. 2026 г., 07:57 31,4 5 окт. 2026 г., 08:16 24,7 5 окт. 2026 г., 08:22 33,7 5 окт. 2026 г., 08:41 27,1 5 окт. 2026 г., 08:47 36,1 5 окт. 2026 г., 09:03 30 5 окт. 2026 г., 09:09 39 5 окт. 2026 г., 09:28 32,4 5 окт. 2026 г., 09:34 41,4 5 окт. 2026 г., 09:53 34,8 5 окт. 2026 г., 09:59 43,8 5 окт. 2026 г., 10:18 37,1 5 окт. 2026 г., 10:24 46,1 5 окт. 2026 г., 10:40 39,9 5 окт. 2026 г., 10:46 48,8 5 окт. 2026 г., 11:05 42 5 окт. 2026 г., 11:11 50,8 5 окт. 2026 г., 11:30 43,9 5 окт. 2026 г., 11:36 52,8 5 окт. 2026 г., 11:55 45,7 5 окт. 2026 г., 12:01 54,5 5 окт. 2026 г., 12:17 47,9 5 окт. 2026 г., 12:26 56 5 окт. 2026 г., 12:42 49,3 5 окт. 2026 г., 12:48 58 5 окт. 2026 г., 13:07 50,5 5 окт. 2026 г., 13:13 59,1 5 окт. 2026 г., 13:32 51,4 5 окт. 2026 г., 13:48 54,2 5 окт. 2026 г., 14:00 91 5 окт. 2026 г., 14:12 98 5 окт. 2026 г., 14:22 87 5 окт. 2026 г., 14:30 53,6 5 окт. 2026 г., 14:39 61,2 5 окт. 2026 г., 14:55 53,6 5 окт. 2026 г., 15:04 61,1 5 окт. 2026 г., 15:20 53,3 5 окт. 2026 г., 15:34 62,6 5 окт. 2026 г., 15:45 52,7 5 окт. 2026 г., 15:51 61 5 окт. 2026 г., 16:10 51,9 5 окт. 2026 г., 16:16 60 5 окт. 2026 г., 16:32 51,7 5 окт. 2026 г., 16:41 58,9 5 окт. 2026 г., 16:57 50,4 5 окт. 2026 г., 17:11 59,1 5 окт. 2026 г., 17:22 48,7 5 окт. 2026 г., 17:36 57,3 5 окт. 2026 г., 17:47 46,9 5 окт. 2026 г., 17:53 54,8 5 окт. 2026 г., 18:09 45,9 5 окт. 2026 г., 18:18 52,7 5 окт. 2026 г., 18:34 43,7 5 окт. 2026 г., 18:48 52 5 окт. 2026 г., 18:59 41,3 5 окт. 2026 г., 19:13 49,5 5 окт. 2026 г., 19:24 38,8 5 окт. 2026 г., 19:30 46,5 5 окт. 2026 г., 19:46 37,2 5 окт. 2026 г., 19:55 43,9 5 окт. 2026 г., 20:11 34,5 5 окт. 2026 г., 20:25 42,5 5 окт. 2026 г., 20:36 31,7 5 окт. 2026 г., 20:50 39,7 5 окт. 2026 г., 21:01 28,9 5 окт. 2026 г., 21:15 36,9 5 окт. 2026 г., 21:23 27,2 5 окт. 2026 г., 21:32 33,8 5 окт. 2026 г., 21:48 24,4 5 окт. 2026 г., 22:02 32,5 5 окт. 2026 г., 22:13 21,7 5 окт. 2026 г., 22:27 29,8 5 окт. 2026 г., 22:38 19 5 окт. 2026 г., 22:52 27,2 5 окт. 2026 г., 23:00 17,6 5 окт. 2026 г., 23:17 24,8 5 окт. 2026 г., 23:25 15,2 5 окт. 2026 г., 23:39 23,6 5 окт. 2026 г., 23:50 13 5 окт. 2026 г., 23:58 13,5 5 окт. 2026 г., 23:59 19,8 Overload: от 80 до 100 Показано 120 из 1440 точек — те же, что нарисованы. Стрелками доступны все. Click a point to add it to the incident.
Два графика с одним курсором
v-model:active-indexсвязывает пару: наведение на любой график двигает курсор в обоих, тултипы называют одну и ту же минуту, а строка над ними сводит её в одну линию. Запросы в минуту и миллисекунды расходятся на два порядка —dual-axisсy-domain-right,y-tick-format-rightиvalue-format-rightздесь осознанный выбор, а не умолчание.size="sm"держит пару компактной.Checkout API · last hour13:59 · 1,232 requests · p95 140 ms · 1 errors Данные графика X Requests / min (левая ось) p95 latency, ms (правая ось) 13:00 1 100 165 13:01 1 176 167 13:02 1 160 169 13:03 1 235 170 13:04 1 217 170 13:05 1 199 170 13:06 1 271 169 13:07 1 250 167 13:08 1 320 165 13:09 1 295 163 13:10 1 269 160 13:11 1 333 156 13:12 1 303 152 13:13 1 363 148 13:14 1 328 144 13:15 1 291 140 13:16 1 344 136 13:17 1 303 132 13:18 1 352 127 13:19 1 306 124 13:20 1 259 120 13:21 1 302 117 13:22 1 252 115 13:23 1 200 113 13:24 1 238 111 13:25 1 184 110 13:26 1 221 110 13:27 1 165 110 13:28 1 109 111 13:29 1 146 113 13:30 1 090 115 13:31 1 126 117 13:32 1 072 120 13:33 1 018 124 13:34 1 057 128 13:35 1 006 132 13:36 1 048 136 13:37 1 000 140 13:38 953 144 13:39 1 001 149 13:40 958 153 13:41 1 010 156 13:42 972 320 13:43 936 323 13:44 995 325 13:45 963 327 13:46 934 329 13:47 999 330 13:48 974 170 13:49 1 042 170 13:50 1 020 169 13:51 1 000 167 13:52 1 073 165 13:53 1 055 163 13:54 1 130 160 13:55 1 113 156 13:56 1 097 152 13:57 1 173 148 13:58 1 157 144 13:59 1 232 140 Данные графика X Errors / min 13:00 0 13:01 3 13:02 2 13:03 1 13:04 0 13:05 3 13:06 2 13:07 1 13:08 0 13:09 3 13:10 2 13:11 1 13:12 0 13:13 3 13:14 2 13:15 1 13:16 0 13:17 3 13:18 2 13:19 1 13:20 0 13:21 3 13:22 2 13:23 1 13:24 0 13:25 3 13:26 2 13:27 1 13:28 0 13:29 3 13:30 2 13:31 1 13:32 0 13:33 3 13:34 2 13:35 1 13:36 0 13:37 3 13:38 2 13:39 1 13:40 0 13:41 3 13:42 18 13:43 23 13:44 21 13:45 19 13:46 24 13:47 22 13:48 0 13:49 3 13:50 2 13:51 1 13:52 0 13:53 3 13:54 2 13:55 1 13:56 0 13:57 3 13:58 2 13:59 1
API порождается из пакета · разойтись не может
Props
| Prop | Type | по умолчанию | Описание |
|---|---|---|---|
xScale | GrChartScaleKind | undefined | undefined | Тип оси X. Не задан — выводится из данных. |
stacked | boolean | "100%" | undefined | false | Складывать серии: каждая полоса ложится на сумму предыдущих. `'100%'` вдобавок нормирует каждую позицию к единице — тогда лента показывает, как менялось **распределение**, а не величины. Собственные значения точек при этом не трогаются: тултип и таблица говорят «сорок», а не «треть». |
fill | "auto" | "gradient" | "solid" | undefined | undefined | Заливка. `auto` — градиент у наложения, плотная у стека. |
height | number | undefined | undefined | Высота холста в пикселях; по умолчанию 256. Данные, загрузка и пустое состояние занимают её одинаково. |
width | number | undefined | 640 | Объявленная ширина: от неё идёт первый рендер, дальше ширина замеряется. |
yDomain | readonly [number | null, number | null] | undefined | undefined | Границы оси значений `[min, max]`; `null` на месте границы — она берётся по данным. |
includeZero | boolean | undefined | false | Дотянуть ось значений до нуля; по умолчанию нет — ось облегает данные. |
references | readonly GrChartReference[] | undefined | undefined | Опорные линии и полосы: порог, план, коридор допустимого. Не серия и нигде ею не считается: в легенду не попадает, индекс палитры не тратит, в стек не входит и в скрытую таблицу уезжает примечанием, а не строкой данных. |
includeReferencesInDomain | boolean | undefined | false | Включить опоры в домен оси. По умолчанию нет, и это осознанно: порог `1.0` при данных около `0.03` растянул бы ось так, что сами данные схлопнулись бы в линию. |
dualAxis | boolean | undefined | false | Показывать вторую ось значений справа. Без неё серии с `axis: 'right'` попадают на левую. Включение осознанное: две оси позволяют подогнать любые два ряда под видимую корреляцию, и это должно быть решением автора графика, а не побочным эффектом поля в данных. |
yDomainRight | readonly [number | null, number | null] | undefined | undefined | Границы правой оси значений при `dualAxis`; `null` на месте границы — она берётся по данным. |
yTickFormatRight | ((value: number) => string) | undefined | undefined | Подпись деления правой оси. Не задана — число по локали. |
valueFormatRight | GrChartNumberFormat | undefined | undefined | Формат значений серий правой оси в тултипе, скрытой таблице и объявлениях. |
xTickCount | number | undefined | undefined | Желаемое число делений оси X; по умолчанию 6. У категорий — потолок числа подписей (не задан — 12). Подписи, которые не помещаются по ширине, прореживаются. |
yTickCount | number | undefined | 5 | Желаемое число делений оси значений; по умолчанию 5. Шаг остаётся «круглым», поэтому делений бывает на одно меньше. |
xTickFormat | ChartTickFormat | undefined | undefined | Подпись деления оси X: `(value, kind) => string`. Не задана — категория, дата или число по локали. |
yTickFormat | ((value: number) => string) | undefined | undefined | Подпись деления оси значений, например `value => value + '%'`. Место под ось считается по отформатированной подписи. |
valueFormat | GrChartNumberFormat | undefined | undefined | Формат значений в тултипе, скрытой таблице и объявлениях: знаки после запятой и разделители. |
curve | GrChartCurve | undefined | undefined | Форма линии между точками: `linear` (по умолчанию), `smooth` или `step`. Сглаживание не выдумывает значений между замерами. |
showPoints | "auto" | "never" | "always" | undefined | "auto" | Маркеры точек: `auto` (по умолчанию) — только на нечастом ряде, `always` или `never`. |
showGrid | "y" | "both" | "x" | "none" | undefined | undefined | Линии сетки: `y` (по умолчанию) — по делениям значений, `x`, `both` или `none`. |
showLegend | boolean | "auto" | undefined | undefined | Легенда серий: `auto` (по умолчанию) — когда серий больше одной; `true` и `false` — всегда и никогда. |
legendPosition | "bottom" | "top" | undefined | undefined | Где стоит легенда: `bottom` (по умолчанию) или `top`. |
tooltip | boolean | undefined | undefined | Панель со значениями под курсором; по умолчанию `true`. `false` прячет только панель: курсор, активные марки, `update:activeIndex` и `pointHover` работают, пока график интерактивен. |
activeIndexv-model | number | null | undefined | undefined | Курсор — `v-model:activeIndex`. Синхронизирует пару графиков. |
loading | boolean | undefined | false | Загрузка: на месте области построения — скелет той же высоты, место под оси уже зарезервировано. |
empty | boolean | undefined | undefined | Пустое состояние явно. Не задано — график пуст, когда рисовать нечего. |
emptyText | string | undefined | undefined | Текст заглушки пустого графика. Не задан — «Нет данных» из переводов пакета. |
dataTable | "hidden" | "visible" | "off" | undefined | undefined | Таблица данных: `hidden` (по умолчанию) — только для скринридера, `visible` — под графиком, `off` — без неё. |
interactive | boolean | undefined | true | `false` — график становится картинкой: без фокуса, тултипа и клавиатуры. |
size | "md" | "xs" | "sm" | "lg" | undefined | undefined | Кегль подписей осей и легенды по контрольной шкале ядра; по умолчанию — размер из `GrConfigProvider`. |
locale | string | undefined | undefined | BCP-47 локаль чисел и дат. Не задана — язык переводов приложения, иначе `en`. |
ariaLabel | string | undefined | undefined | Доступное имя графика. Не задано — сводка, которую собирает компонент: тип графика и объём данных. |
ariaDescription | string | undefined | undefined | Описание для скринридера — вывод, ради которого график показан; дополняет сводку, а не заменяет её. |
decimate | "auto" | "never" | "always" | undefined | undefined | Когда прореживать ряд для рисунка (LTTB). `'auto'` включается, только когда точек больше бюджета: выше двух вершин на пиксель SVG всё равно не покажет того, что выбросил бы алгоритм, а платит за это длиной строки `d`. Прорежённые точки идут **только** в рисунок — курсор, клавиатура, тултип и скрытая таблица знают полный ряд. |
maxPoints | number | undefined | undefined | Бюджет точек на серию. Не задан — считается от ширины области построения. |
canvasThreshold | number | undefined | GR_CHART_CANVAS_THRESHOLD | Порог, выше которого марки не рисуются даже при `showPoints: 'always'`. На `'auto'` при дефолтах не влияет: тот отсекает марки раньше, на `AUTO_MARKERS_LIMIT`. Влиять начинает, если задать порог ниже него. |
zoom | GrChartZoom | undefined | undefined | Какими жестами пользователь меняет видимое окно. По умолчанию — никакими. Управляется только указателем; клавиатурного пути к окну у графика нет. Поэтому окно и выведено наружу как `v-model:xWindow` — приложение обязано дать к нему свой доступный путь: кнопку сброса, поля диапазона. |
xWindowv-model | readonly [GrChartXValue, GrChartXValue] | null | undefined | undefined | Видимое окно по абсциссе — `v-model:xWindow`. `null` — весь ряд. Окно **выбирает данные**, а не обрезает рисунок: по нему считаются позиции, курсор, клавиатура, скрытая таблица и размах оси значений. Прореживание — противоположный случай, оно рисунку невидимо и полный ряд не трогает. Отсюда же следствие: `activeIndex` адресует текущее окно. |
dataTableMaxRows | number | "auto" | undefined | undefined | Потолок строк скрытой таблицы данных. `'auto'` (по умолчанию) — столько же, сколько вершин в рисунке: выше потолка таблица печатает те же точки, что нарисованы, и говорит об этом пометкой. Число задаёт свой потолок, `Infinity` снимает его совсем, `dataTable: 'off'` убирает таблицу целиком — что из этого нужно, решает приложение. |
seriesобязательный | readonly number[] | readonly GrChartSeries[] | — | Серии либо голый ряд чисел — тогда `x` становится порядковым номером. |
Слоты
| Slot | Type | Описание |
|---|---|---|
tooltip | { active: GrChartActivePoint; formatValue: (value: number | null) => string; } | Своё содержимое панели тултипа вместо стандартного; данные активной позиции — в параметрах слота. |
legend | { series: readonly NormalizedSeries[]; toggle: (id: string) => void; } | Своя легенда вместо стандартной. У пустого графика не рисуется. |
empty | any | Своя заглушка пустого графика вместо «Нет данных»; занимает ту же `height`. |
header | any | Заголовок над графиком, внутри его корня — выше легенды, стоящей сверху. |
События
| Event | Сигнатура | Описание |
|---|---|---|
update:hiddenSeries | (event: "update:hiddenSeries", value: string[]): void | — |
update:activeIndex | (event: "update:activeIndex", value: number | null): void | — |
update:xWindow | (event: "update:xWindow", value: GrChartXWindow | null): void | — |
pointClick | (event: "pointClick", value: GrChartActivePoint): void | — |
pointHover | (event: "pointHover", value: GrChartActivePoint | null): void | — |
legendToggle | (event: "legendToggle", value: { seriesId: string; hidden: boolean; }): void | — |
Методы
| Methods | Сигнатура | Описание |
|---|---|---|
element | HTMLElement | null | Корневой элемент — для замеров и скролла в потребителе. |
Типы
Все экспортируемые типы подпути, по файлам, где они объявлены. Имена, дженерики и тела читаются из файлов деклараций пакета и разойтись не могут.
import type { GrChartAreaConfigurableProps, GrChartSize, GrChartAreaProps } from '@feugene/granularity-charts/components/GrChartArea'Файлdist/types/components/GrChartArea/config.d.ts
group тот же, что у остальных графиков: рама у них общая, и её чанк тоже.
Ребром графа компонентов общий чанк не становится — иначе вынесенный хелпер
превращал бы соседей в зависимости друг друга; в файлы каждого дотянувшегося
компонента он входит, и классы рамы сборка извлекает оттуда сама.
GrEmptyState и GrSkeleton объявлены зависимостями потому, что рама их
**рендерит**: без объявления они не попадут в замыкание селекции, и
приложение не подмешает их CSS.
const grChartAreaConfig: import("@feugene/granum/contract").GranumComponentDescriptor<"GrChartArea">;Файлdist/types/components/GrChartArea/defaults.d.ts
Пропы GrChartArea, настраиваемые глобально через
<GrConfigProvider :component-defaults="{ GrChartArea: { … } }">.
Только оформление: данные, стек и границы осей задаются на месте.
interface GrChartAreaConfigurableProps {
/**
* Когда прореживать ряд для рисунка. Политика рендера — приложение с плотными
* рядами задаёт её один раз на всё поддерево.
*/
decimate: 'auto' | 'always' | 'never';
/** Бюджет точек на серию. */
maxPoints: number;
/**
* Какими жестами меняется видимое окно.
*
* Политика приложения, а не свойство отдельного графика: включать
* приближение на одной панели и не включать на соседней — это разные правила
* поведения у одинаковых с виду картинок.
*/
zoom: GrChartZoom;
/**
* Потолок строк скрытой таблицы данных.
*
* Политика приложения: держать ли полный ряд в дереве доступности, усечь ли
* его до нарисованного или убрать таблицу вовсе — решение уровня продукта, а
* не отдельного графика.
*/
dataTableMaxRows: number | 'auto';
size: GrChartSize;
height: number;
curve: GrChartCurve;
fill: 'auto' | 'gradient' | 'solid';
showGrid: 'both' | 'x' | 'y' | 'none';
showLegend: boolean | 'auto';
legendPosition: 'top' | 'bottom';
tooltip: boolean;
dataTable: 'hidden' | 'visible' | 'off';
}Файлdist/types/components/GrChartFrame/chartFrameStyles.d.ts
Классы общей рамы графика.
Рама — не компонент: у директории нет ни index.ts, ни config.ts, поэтому
в реестры она не попадает (гейт frameOwnership.test.ts). Владельцем токенов
--gr-chart-frame-* она при этом остаётся: гейт покомпонентных токенов ищет
реестры по файлу tokens.json в любой директории Gr…, а не по составу
компонента.
Пиксельных литералов и утилит uno-шкалы (text-sm, rounded-md) здесь нет:
темой они не настраиваются, а выглядят правильно.
type GrChartSize = GrComponentSize;Файлdist/types/components/GrChartArea/safelist.d.ts
const grChartAreaSafelist: string[];Файлdist/types/components/GrChartArea/GrChartArea.vue.d.ts
Площадь: тот же ряд, что у линии, но с заливкой до базовой линии — и складываемый в стек. Отдельным компонентом, а не пропом линии: взявший линию не должен получать в бандл арифметику стека и разметку градиентов, которых он не просил.
interface GrChartAreaProps {
/** Серии либо голый ряд чисел — тогда `x` становится порядковым номером. */
series: readonly GrChartSeries[] | readonly number[];
/** Тип оси X. Не задан — выводится из данных. */
xScale?: GrChartScaleKind;
/**
* Складывать серии: каждая полоса ложится на сумму предыдущих.
*
* `'100%'` вдобавок нормирует каждую позицию к единице — тогда лента
* показывает, как менялось **распределение**, а не величины. Собственные
* значения точек при этом не трогаются: тултип и таблица говорят «сорок», а
* не «треть».
*/
stacked?: boolean | '100%';
/** Заливка. `auto` — градиент у наложения, плотная у стека. */
fill?: 'auto' | 'gradient' | 'solid';
/**
* Высота холста в пикселях; по умолчанию 256. Данные, загрузка и пустое состояние занимают её
* одинаково.
*/
height?: number;
/** Объявленная ширина: от неё идёт первый рендер, дальше ширина замеряется. */
width?: number;
/** Границы оси значений `[min, max]`; `null` на месте границы — она берётся по данным. */
yDomain?: readonly [number | null, number | null];
/** Дотянуть ось значений до нуля; по умолчанию нет — ось облегает данные. */
includeZero?: boolean;
/**
* Опорные линии и полосы: порог, план, коридор допустимого.
*
* Не серия и нигде ею не считается: в легенду не попадает, индекс палитры не
* тратит, в стек не входит и в скрытую таблицу уезжает примечанием, а не
* строкой данных.
*/
references?: readonly GrChartReference[];
/**
* Включить опоры в домен оси.
*
* По умолчанию нет, и это осознанно: порог `1.0` при данных около `0.03`
* растянул бы ось так, что сами данные схлопнулись бы в линию.
*/
includeReferencesInDomain?: boolean;
/**
* Показывать вторую ось значений справа.
*
* Без неё серии с `axis: 'right'` попадают на левую. Включение осознанное:
* две оси позволяют подогнать любые два ряда под видимую корреляцию, и это
* должно быть решением автора графика, а не побочным эффектом поля в данных.
*/
dualAxis?: boolean;
/**
* Границы правой оси значений при `dualAxis`; `null` на месте границы — она берётся по данным.
*/
yDomainRight?: readonly [number | null, number | null];
/** Подпись деления правой оси. Не задана — число по локали. */
yTickFormatRight?: (value: number) => string;interface GrChartAreaEmits {
/**
* Легенда просит скрыть или показать серию — новый список id; применяет его потребитель
* (`v-model:hiddenSeries`).
*/
(e: 'update:hiddenSeries', value: string[]): void;
/** Курсор сдвинулся: индекс позиции или `null` — для `v-model:activeIndex`. */
(e: 'update:activeIndex', value: number | null): void;
/** Жест приближения сменил видимое окно — для `v-model:xWindow`. */
(e: 'update:xWindow', value: GrChartXWindow | null): void;
/** Щелчок или Enter по активной позиции — со значениями всех видимых серий в ней. */
(e: 'pointClick', value: GrChartActivePoint): void;
/** Курсор пришёл на позицию или ушёл с графика (`null`). */
(e: 'pointHover', value: GrChartActivePoint | null): void;
/** Нажат пункт легенды: какая серия и в какое состояние просится. */
(e: 'legendToggle', value: {
seriesId: string;
hidden: boolean;
}): void;
}Доступность
Паттерн APG
При нескольких сериях ↑/↓ переключают читаемую серию
| Клавиша | Действие |
|---|---|
| — | точка ряда по оси X |
Полный контракт пакета: docs/keyboard.md ↗
Использование из прозы библиотеки
Выше порога рисует холст
Тело графика умеет рисоваться двумя способами. Ниже порога это SVG, выше —
<canvas>; выбирает сам компонент, пропа «каким рендерером» нет.
Порог считается в нарисованных вершинах, а не в точках — canvasThreshold,
по умолчанию 24 000. Разница существенная: прореживание режет каждый ряд
до предела экрана (около двух вершин на пиксель), поэтому один ряд в сто тысяч
точек рисуется как 2400 вершин и стоит миллисекунды, а двадцать рядов по 2400 —
те же 48 000 точек — стоят шестнадцати, то есть целого кадра.
Числа замера при ширине 1200px, 2400 вершин на ряд:
| Рядов | SVG | Холст |
|---|---|---|
| 1 | 1,1 мс | 0,4 мс |
| 8 | 6,7 мс | 0,6 мс |
| 20 | 16,3 мс | 1,7 мс |
canvasThreshold: 0 выключает холст совсем — на случай, когда рисунок обязан
остаться векторным: печать, экспорт SVG, свой CSS поверх марок.
Доступность от смены рендерера не меняется вовсе. Курсор, клавиатура,
тултип и скрытая таблица работают с оверлеем и с полными рядами, а не с марками:
холст для них не существует, он aria-hidden и не ловит указатель. Это и было
условием, при котором второй рендерер вообще допустили.
Что холст рисует иначе. Сетка переезжает в него же: холст лежит под <svg>,
чтобы оси и активная точка остались сверху, — а сетка обязана остаться под
рядами. У площади градиентная заливка становится сплошной: url(#…) холст не
понимает, а на двадцати площадях градиент всё равно читается как каша.
Заливка выбирается по режиму, а не по вкусу
fill: 'auto' — градиент у наложения и плотная заливка у стека. Причина в
разном: наложенным рядам нужно просвечивать друг сквозь друга, а полосы стека
стоят встык, и градиент размыл бы границу между двумя соседними — то есть само
место, где кончается одна часть и начинается другая.
Значение точки остаётся своим
В стеке на точку приезжают границы полосы отдельными полями, но собственное y
не трогается. Тултип, скрытая таблица и живой регион говорят «партнёры — сто
девяносто», а не «шестьсот пятьдесят, потому что снизу лежит розница».
Скрытая серия из стека выпадает, лежащие выше опускаются. Ось значений считается по вершинам полос и всегда включает ноль: стек от ненулевой базы врёт про пропорции.
Стек строят по полным рядам. Пропуск — единственное место, где он честен не полностью: сумма в этой позиции занижена. Протянуть последнее известное значение было бы хуже — это нарисовать данные, которых не было.
Сто процентов отвечают на другой вопрос
stacked: true показывает величины и их сумму, stacked: '100%' — только
распределение: сумма в каждой позиции равна единице, и лента говорит, как
менялись доли, а не сколько всего было. Выбирать надо один вопрос: читатель не
знает, сравнивать ему высоты лент или их доли.
Нормируется рисунок, а не данные. Ось переходит в проценты, а тултип,
скрытая таблица и живой регион по-прежнему называют абсолютные величины.
Позиция с нулевой суммой нормировать не на что — там ноль, а не NaN.
Длинный ряд сокращается в рисунке, а не в данных
decimate: 'auto' (по умолчанию) прореживает вершины пути, когда точек больше, чем экран способен показать.
В стопке набор абсцисс общий на все серии — иначе низ верхней полосы интерполировался бы по одним X, а верх нижней
по другим, и заливка разошлась бы швами. Курсор, клавиатура, тултип и скрытая таблица знают полный ряд; разбор —
../model.md, раздел «Прореживание — проекция, а не данные».
Приближение по абсциссе
zoom включает окно: 'brush' — протяжка по холсту, 'wheel' — колесо,
'both' — оба. По умолчанию выключено.
<GrChartArea v-model:x-window="window" :series="series" zoom="both" />
<GrButton :disabled="window === null" @click="window = null">
Весь ряд
</GrButton>Окно выбирает данные, а не обрезает рисунок: по нему считаются позиции, курсор, клавиатура, скрытая таблица и размах оси значений. Практическое следствие — приближение проявляет мелкую структуру, которая на полном ряде ложится сплошной штриховкой: бюджет прореживания считается от ширины области, а точек в окне меньше, и на каждую приходится больше вершин.
Клавиатура работает всегда, когда включён zoom: +/- приближают к активной
точке, Shift+стрелки сдвигают окно, 0 возвращает весь ряд. Union пропа
перечисляет только жесты указателя — отключаемой клавиатуры у приближения
нет by design (../a11y.md, раздел про приближение).
v-model:x-window не обязателен — без привязки график приближается сам.
Привязывают его ради другого: синхронной пары графиков, кнопки сброса рядом с
холстом, сохранения приближения в адресной строке.
Границы принимаются в том же виде, что абсциссы точек (Date, ISO-строка,
число), наружу уходят числами. activeIndex при заданном окне адресует его,
а не весь ряд.
Скрытая таблица и её потолок
Полные данные графика строками — то, что читает диктор вместо картинки. По умолчанию dataTable: 'hidden': в дереве
доступности, глазами не видна.
Строка на точку читаема, пока строк немного. Поэтому у таблицы есть потолок — dataTableMaxRows, по умолчанию
'auto', то есть бюджет рисунка:
<GrChartArea :series="series" /> <!-- auto: как нарисовано -->
<GrChartArea :series="series" :data-table-max-rows="200" /> <!-- свой потолок -->
<GrChartArea :series="series" :data-table-max-rows="Infinity" /> <!-- всегда полная -->
<GrChartArea :series="series" data-table="off" /> <!-- таблицы нет вовсе -->Выше потолка таблица печатает те же точки, что нарисованы, и говорит об этом пометкой в подвале. Поточечная
полнота при этом не теряется: стрелки обходят весь ряд и проговаривают каждую точку. Таблица отвечает за обзор,
клавиатура — за точное значение; разбор — ../model.md.
'auto' — это «столько строк, сколько можно прочитать». Бюджет рисунка берётся, когда он есть; при
decimate: 'never' его нет, и остаётся фиксированный потолок с равномерной выборкой.
Что из этого нужно, решает приложение: держать десять тысяч строк в дереве доступности — его право, но и цена перестроения такой таблицы на нём.
Порог рисуется опорой, а не серией
План, норма и граница допустимого — это проп references, а не ряд из константы: серия-константа попала бы в
легенду, растянула бы ось и уехала бы в таблицу как данные. Разбор — ../model.md, раздел
«Опора — не серия».
Две оси — осознанное решение
Ряды разного порядка (деньги и штуки) читаются на одном графике только с двумя
осями, а две оси позволяют подогнать любую пару под видимую корреляцию. Поэтому
axis: 'right' у серии не работает, пока не включён dualAxis. Инварианты —
../model.md, раздел «Вторая ось значений».
Пропы этого примера