@evergis/react 4.0.153 → 4.0.154
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Dashboard/componentTypes.d.ts +3 -3
- package/dist/components/Dashboard/components/Chart/ChartPlotContext.d.ts +24 -0
- package/dist/components/Dashboard/components/Chart/components/AxisTitles.d.ts +23 -0
- package/dist/components/Dashboard/components/Chart/styled.d.ts +33 -0
- package/dist/components/Dashboard/components/ChartLegend/index.d.ts +1 -0
- package/dist/components/Dashboard/components/ChartLegend/styled.d.ts +1 -0
- package/dist/components/Dashboard/constants.d.ts +37 -1
- package/dist/components/Dashboard/containers/ChartContainer/types.d.ts +3 -1
- package/dist/components/Dashboard/containers/FiltersContainer/constants.d.ts +1 -0
- package/dist/components/Dashboard/containers/styled.d.ts +38 -0
- package/dist/components/Dashboard/hooks/index.d.ts +3 -0
- package/dist/components/Dashboard/hooks/useChartAxisAttributes.d.ts +19 -0
- package/dist/components/Dashboard/hooks/useChartAxisTickFormat.d.ts +18 -0
- package/dist/components/Dashboard/hooks/useChartAxisTitles.d.ts +32 -0
- package/dist/components/Dashboard/types.d.ts +59 -1
- package/dist/components/Dashboard/utils/chartAxis.d.ts +29 -0
- package/dist/components/Dashboard/utils/index.d.ts +1 -0
- package/dist/index.js +617 -85
- package/dist/index.js.map +1 -1
- package/dist/react.esm.js +600 -86
- package/dist/react.esm.js.map +1 -1
- package/package.json +3 -3
package/dist/react.esm.js
CHANGED
|
@@ -3356,6 +3356,46 @@ const MAX_CHART_WIDTH = 300;
|
|
|
3356
3356
|
const DEFAULT_CHART_ANGLE = 4;
|
|
3357
3357
|
const DEFAULT_CHART_HEIGHT = 90;
|
|
3358
3358
|
const STACK_BAR_TOTAL_HEIGHT = 20;
|
|
3359
|
+
/** Высота строки текста подписи оси (шрифт 10px) — по макету. */
|
|
3360
|
+
const AXIS_TITLE_LINE_HEIGHT = 12;
|
|
3361
|
+
/** Зазор между подписью оси и значениями шкалы — по макету. */
|
|
3362
|
+
const AXIS_TITLE_GAP = 4;
|
|
3363
|
+
/**
|
|
3364
|
+
* Поле SVG графика под выступ крайних делений шкалы значений.
|
|
3365
|
+
*
|
|
3366
|
+
* d3 центрирует подпись деления на его линии (`dy: 0.32em`), поэтому у крайнего деления половина подписи
|
|
3367
|
+
* выходит за поле графика. Если поле вплотную к краю SVG, половина оказывается за SVG, и её срезает
|
|
3368
|
+
* обёртка: у линейного графика в fill — `ChartFillMeasure` (`overflow: hidden`), у барчарта всегда —
|
|
3369
|
+
* `BarChartContainer` (`overflow-x: hidden`, отчего и по вертикали содержимое не `visible`).
|
|
3370
|
+
*/
|
|
3371
|
+
const Y_AXIS_LABEL_OVERHANG = 6;
|
|
3372
|
+
/** Зазор от строки горизонтальных подписей осей до верхней линии сетки — по макету. */
|
|
3373
|
+
const AXIS_TITLE_TOP_GRID_GAP = 9;
|
|
3374
|
+
/** Число делений шкал линейного графика; у левой и правой шкал оно общее, чтобы совпадала сетка. */
|
|
3375
|
+
const LINE_CHART_Y_TICKS = 4;
|
|
3376
|
+
/**
|
|
3377
|
+
* Высота строки горизонтальных подписей осей (`axis.titlePosition: "top"`). Вместе с верхним полем SVG
|
|
3378
|
+
* (Y_AXIS_LABEL_OVERHANG) даёт строку текста и 9px до верхней линии сетки: деление центрировано на
|
|
3379
|
+
* линии и выступает над ней на ~5px, так что между подписью и значением шкалы остаются те же 4px,
|
|
3380
|
+
* что и у вертикальной подписи.
|
|
3381
|
+
*/
|
|
3382
|
+
const AXIS_TITLE_TOP_HEIGHT = AXIS_TITLE_LINE_HEIGHT + AXIS_TITLE_TOP_GRID_GAP - Y_AXIS_LABEL_OVERHANG;
|
|
3383
|
+
/**
|
|
3384
|
+
* Пустая полоса под подписями оси X внутри SVG линейного графика: под ось зарезервировано
|
|
3385
|
+
* LINE_CHART_LABEL_MARGIN (20px), а подписи сдвинуты вниз на +16px, поэтому строка подписи
|
|
3386
|
+
* (шрифт d3 10px) кончается примерно в 14px от низа SVG.
|
|
3387
|
+
*/
|
|
3388
|
+
const LINE_CHART_X_LABELS_BLANK = 14;
|
|
3389
|
+
/** Зазор между подписями оси X и подписью самой оси — по макету. */
|
|
3390
|
+
const X_AXIS_TITLE_GAP = 4;
|
|
3391
|
+
/** Зазор между подписью оси X и легендой, идущей отдельной строкой, — по макету. */
|
|
3392
|
+
const X_AXIS_TITLE_LEGEND_GAP = 8;
|
|
3393
|
+
/** Выравнивание подписи оси X → `justify-content` строки-подвала графика. */
|
|
3394
|
+
const CHART_AXIS_ALIGN_JUSTIFY = {
|
|
3395
|
+
left: "flex-start",
|
|
3396
|
+
center: "center",
|
|
3397
|
+
right: "flex-end",
|
|
3398
|
+
};
|
|
3359
3399
|
const FILTER_PREFIX = "%";
|
|
3360
3400
|
/** Имя системного геометрического фильтра — выделение, нарисованное пользователем на карте. */
|
|
3361
3401
|
const GEOMETRY_FILTER_NAME = "geometry";
|
|
@@ -3465,7 +3505,76 @@ const CONTAINER_BODY_FILL_STYLE = {
|
|
|
3465
3505
|
*/
|
|
3466
3506
|
const CONTAINERS_GROUP_DEFAULTS = { boxSizing: "border-box" };
|
|
3467
3507
|
|
|
3468
|
-
|
|
3508
|
+
/** Обёртка линейного графика: строка горизонтальных подписей над телом, вертикальные — по бокам. */
|
|
3509
|
+
const LineChartLayout = styled.div.withConfig({ displayName: "LineChartLayout", componentId: "sc-gmzloe" }) `
|
|
3510
|
+
display: flex;
|
|
3511
|
+
flex-direction: column;
|
|
3512
|
+
width: 100%;
|
|
3513
|
+
height: 100%;
|
|
3514
|
+
min-width: 0;
|
|
3515
|
+
min-height: 0;
|
|
3516
|
+
`;
|
|
3517
|
+
const LineChartRow = styled.div.withConfig({ displayName: "LineChartRow", componentId: "sc-dxzi1m" }) `
|
|
3518
|
+
display: flex;
|
|
3519
|
+
flex: 1 1 auto;
|
|
3520
|
+
align-items: stretch;
|
|
3521
|
+
min-width: 0;
|
|
3522
|
+
min-height: 0;
|
|
3523
|
+
`;
|
|
3524
|
+
/**
|
|
3525
|
+
* Тело линейного графика между вертикальными подписями осей. Забирает всю оставшуюся ширину строки —
|
|
3526
|
+
* её и измеряем, чтобы отдать d3 пиксельную ширину: подписи бывают в одну и в две строки.
|
|
3527
|
+
*/
|
|
3528
|
+
const LineChartBody = styled.div.withConfig({ displayName: "LineChartBody", componentId: "sc-1sbsc7u" }) `
|
|
3529
|
+
flex: 1 1 auto;
|
|
3530
|
+
min-width: 0;
|
|
3531
|
+
`;
|
|
3532
|
+
const AxisTitlesRow = styled.div.withConfig({ displayName: "AxisTitlesRow", componentId: "sc-1hskx6f" }) `
|
|
3533
|
+
display: flex;
|
|
3534
|
+
flex: 0 0 ${AXIS_TITLE_TOP_HEIGHT}px;
|
|
3535
|
+
justify-content: space-between;
|
|
3536
|
+
align-items: flex-start;
|
|
3537
|
+
gap: 0.5rem;
|
|
3538
|
+
height: ${AXIS_TITLE_TOP_HEIGHT}px;
|
|
3539
|
+
min-width: 0;
|
|
3540
|
+
`;
|
|
3541
|
+
const AxisTitleText = styled.div.withConfig({ displayName: "AxisTitleText", componentId: "sc-9shs4l" }) `
|
|
3542
|
+
font-size: 0.625rem;
|
|
3543
|
+
line-height: ${AXIS_TITLE_LINE_HEIGHT}px;
|
|
3544
|
+
color: ${({ $color, theme: { palette } }) => $color || palette.iconDisabled};
|
|
3545
|
+
`;
|
|
3546
|
+
const AxisTitleTop = styled(AxisTitleText).withConfig({ displayName: "AxisTitleTop", componentId: "sc-pv3dgm" }) `
|
|
3547
|
+
overflow: hidden;
|
|
3548
|
+
white-space: nowrap;
|
|
3549
|
+
text-overflow: ellipsis;
|
|
3550
|
+
`;
|
|
3551
|
+
/**
|
|
3552
|
+
* Колонка вертикальной подписи оси: ширина — по тексту (одна или две строки) плюс зазор до значений
|
|
3553
|
+
* шкалы. Вертикальные отступы колонки повторяют поля SVG, поэтому подпись центрируется по полю
|
|
3554
|
+
* графика, а не по всей высоте вместе с подписями оси X.
|
|
3555
|
+
*/
|
|
3556
|
+
const AxisTitleSideColumn = styled.div.withConfig({ displayName: "AxisTitleSideColumn", componentId: "sc-11nmkfu" }) `
|
|
3557
|
+
display: flex;
|
|
3558
|
+
flex: 0 0 auto;
|
|
3559
|
+
align-items: center;
|
|
3560
|
+
justify-content: center;
|
|
3561
|
+
box-sizing: border-box;
|
|
3562
|
+
padding: ${({ $plotTop }) => $plotTop}px 0 ${({ $plotBottom }) => $plotBottom}px;
|
|
3563
|
+
${({ $side }) => ($side === "left" ? "padding-right" : "padding-left")}: ${AXIS_TITLE_GAP}px;
|
|
3564
|
+
`;
|
|
3565
|
+
/**
|
|
3566
|
+
* Сам текст вертикальной подписи. Поворот вынесен на внутренний элемент: повёрнутая целиком колонка
|
|
3567
|
+
* перенесла бы зазор до шкалы на внешнюю сторону. Левая подпись читается снизу вверх, правая — сверху
|
|
3568
|
+
* вниз, как на макете.
|
|
3569
|
+
*/
|
|
3570
|
+
const AxisTitleSide = styled(AxisTitleText).withConfig({ displayName: "AxisTitleSide", componentId: "sc-lretfl" }) `
|
|
3571
|
+
max-height: 100%;
|
|
3572
|
+
overflow: hidden;
|
|
3573
|
+
text-align: center;
|
|
3574
|
+
writing-mode: vertical-rl;
|
|
3575
|
+
transform: ${({ $side }) => ($side === "left" ? "rotate(180deg)" : "none")};
|
|
3576
|
+
`;
|
|
3577
|
+
const ChartTooltipTable = styled.table.withConfig({ displayName: "ChartTooltipTable", componentId: "sc-1j0a1z" }) `
|
|
3469
3578
|
td {
|
|
3470
3579
|
padding: 0;
|
|
3471
3580
|
}
|
|
@@ -3474,7 +3583,7 @@ const ChartTooltipTable = styled.table.withConfig({ displayName: "ChartTooltipTa
|
|
|
3474
3583
|
padding-bottom: 0.375rem;
|
|
3475
3584
|
}
|
|
3476
3585
|
`;
|
|
3477
|
-
const ChartTooltip = styled(Flex).withConfig({ displayName: "ChartTooltip", componentId: "sc-
|
|
3586
|
+
const ChartTooltip = styled(Flex).withConfig({ displayName: "ChartTooltip", componentId: "sc-1ps09qa" }) `
|
|
3478
3587
|
flex-wrap: nowrap;
|
|
3479
3588
|
background: rgb(48, 69, 79);
|
|
3480
3589
|
border-radius: 0.25rem;
|
|
@@ -3484,26 +3593,26 @@ const ChartTooltip = styled(Flex).withConfig({ displayName: "ChartTooltip", comp
|
|
|
3484
3593
|
margin-bottom: 0.25rem;
|
|
3485
3594
|
}
|
|
3486
3595
|
`;
|
|
3487
|
-
const ChartTooltipLabel = styled.div.withConfig({ displayName: "ChartTooltipLabel", componentId: "sc-
|
|
3596
|
+
const ChartTooltipLabel = styled.div.withConfig({ displayName: "ChartTooltipLabel", componentId: "sc-1chgokj" }) `
|
|
3488
3597
|
margin-right: 0.25rem;
|
|
3489
3598
|
`;
|
|
3490
|
-
const ChartTooltipColor = styled.div.withConfig({ displayName: "ChartTooltipColor", componentId: "sc-
|
|
3599
|
+
const ChartTooltipColor = styled.div.withConfig({ displayName: "ChartTooltipColor", componentId: "sc-1un94mw" }) `
|
|
3491
3600
|
width: 0.625rem;
|
|
3492
3601
|
height: 0.625rem;
|
|
3493
3602
|
background-color: ${({ $color }) => $color};
|
|
3494
3603
|
border-radius: ${({ theme: { borderRadius } }) => borderRadius.smallest};
|
|
3495
3604
|
margin-right: 0.25rem;
|
|
3496
3605
|
`;
|
|
3497
|
-
const ChartLegendColor$1 = styled.div.withConfig({ displayName: "ChartLegendColor", componentId: "sc-
|
|
3606
|
+
const ChartLegendColor$1 = styled.div.withConfig({ displayName: "ChartLegendColor", componentId: "sc-sw1cfw" }) `
|
|
3498
3607
|
width: 0.5rem;
|
|
3499
3608
|
height: 0.5rem;
|
|
3500
3609
|
background-color: ${({ $color }) => $color};
|
|
3501
3610
|
border-radius: 0.125rem;
|
|
3502
3611
|
`;
|
|
3503
|
-
const ChartLegendValue = styled.div.withConfig({ displayName: "ChartLegendValue", componentId: "sc-
|
|
3612
|
+
const ChartLegendValue = styled.div.withConfig({ displayName: "ChartLegendValue", componentId: "sc-1s1kjum" }) `
|
|
3504
3613
|
opacity: 0.65;
|
|
3505
3614
|
`;
|
|
3506
|
-
const ChartTooltipRow = styled(Flex).withConfig({ displayName: "ChartTooltipRow", componentId: "sc-
|
|
3615
|
+
const ChartTooltipRow = styled(Flex).withConfig({ displayName: "ChartTooltipRow", componentId: "sc-ftllia" }) `
|
|
3507
3616
|
display: flex;
|
|
3508
3617
|
flex-direction: row;
|
|
3509
3618
|
flex-wrap: nowrap;
|
|
@@ -3515,11 +3624,11 @@ const ChartTooltipRow = styled(Flex).withConfig({ displayName: "ChartTooltipRow"
|
|
|
3515
3624
|
margin-right: 0.25rem;
|
|
3516
3625
|
}
|
|
3517
3626
|
`;
|
|
3518
|
-
const ChartTooltipName = styled.div.withConfig({ displayName: "ChartTooltipName", componentId: "sc-
|
|
3627
|
+
const ChartTooltipName = styled.div.withConfig({ displayName: "ChartTooltipName", componentId: "sc-16ov53z" }) `
|
|
3519
3628
|
margin-right: 1rem;
|
|
3520
3629
|
opacity: 0.65;
|
|
3521
3630
|
`;
|
|
3522
|
-
const PieChartCenter = styled.div.withConfig({ displayName: "PieChartCenter", componentId: "sc-
|
|
3631
|
+
const PieChartCenter = styled.div.withConfig({ displayName: "PieChartCenter", componentId: "sc-5m536c" }) `
|
|
3523
3632
|
position: absolute;
|
|
3524
3633
|
top: 50%;
|
|
3525
3634
|
left: 50%;
|
|
@@ -3528,7 +3637,7 @@ const PieChartCenter = styled.div.withConfig({ displayName: "PieChartCenter", co
|
|
|
3528
3637
|
font-weight: bold;
|
|
3529
3638
|
font-size: 1.5rem;
|
|
3530
3639
|
`;
|
|
3531
|
-
const ChartWrapperContainer = styled.div.withConfig({ displayName: "ChartWrapperContainer", componentId: "sc-
|
|
3640
|
+
const ChartWrapperContainer = styled.div.withConfig({ displayName: "ChartWrapperContainer", componentId: "sc-1ixngl" }) `
|
|
3532
3641
|
position: relative;
|
|
3533
3642
|
width: 100%;
|
|
3534
3643
|
`;
|
|
@@ -3537,7 +3646,7 @@ const ChartWrapperContainer = styled.div.withConfig({ displayName: "ChartWrapper
|
|
|
3537
3646
|
* на неё вешается ref для ResizeObserver — меряем обе оси без цикла. Плоский div (не Flex uilib), как соседний
|
|
3538
3647
|
* ChartWrapperContainer, чтобы ref гарантированно дошёл до DOM-узла. Тело графика центрируется внутри.
|
|
3539
3648
|
*/
|
|
3540
|
-
const ChartFillMeasure = styled.div.withConfig({ displayName: "ChartFillMeasure", componentId: "sc-
|
|
3649
|
+
const ChartFillMeasure = styled.div.withConfig({ displayName: "ChartFillMeasure", componentId: "sc-3rqqmt" }) `
|
|
3541
3650
|
position: relative;
|
|
3542
3651
|
display: flex;
|
|
3543
3652
|
align-items: center;
|
|
@@ -3555,7 +3664,7 @@ const ChartFillMeasure = styled.div.withConfig({ displayName: "ChartFillMeasure"
|
|
|
3555
3664
|
display: block;
|
|
3556
3665
|
}
|
|
3557
3666
|
`;
|
|
3558
|
-
const Tooltip = styled.div.withConfig({ displayName: "Tooltip", componentId: "sc-
|
|
3667
|
+
const Tooltip = styled.div.withConfig({ displayName: "Tooltip", componentId: "sc-k91v0" }) `
|
|
3559
3668
|
position: relative;
|
|
3560
3669
|
border-radius: 0.25rem;
|
|
3561
3670
|
background-color: rgba(28, 33, 48);
|
|
@@ -3660,7 +3769,7 @@ const LineChartStyles = createGlobalStyle `
|
|
|
3660
3769
|
fill: ${({ theme: { palette } }) => palette.textDisabled};
|
|
3661
3770
|
}
|
|
3662
3771
|
`;
|
|
3663
|
-
const StyledBarChart = styled(BarChart$1).withConfig({ displayName: "StyledBarChart", componentId: "sc-
|
|
3772
|
+
const StyledBarChart = styled(BarChart$1).withConfig({ displayName: "StyledBarChart", componentId: "sc-16gz38d" }) `
|
|
3664
3773
|
.domain {
|
|
3665
3774
|
display: none;
|
|
3666
3775
|
}
|
|
@@ -4548,6 +4657,79 @@ const getAttributeConfigurationByName = (attributes, name) => {
|
|
|
4548
4657
|
return attributes[name];
|
|
4549
4658
|
};
|
|
4550
4659
|
|
|
4660
|
+
const EMPTY_AXIS = {};
|
|
4661
|
+
const warnedLegacySources = new Set();
|
|
4662
|
+
// Сборщик консьюмера подставляет `process.env.NODE_ENV` строкой, поэтому выражение должно быть
|
|
4663
|
+
// ровно таким — без `typeof process` и без `?.`. Сам `process` webpack 5 в браузер не завозит:
|
|
4664
|
+
// проверка `typeof process` отключила бы предупреждения и в dev. Консьюмер без сборщика получит
|
|
4665
|
+
// ReferenceError — он гасится, и предупреждений просто нет.
|
|
4666
|
+
const isDevEnvironment = (() => {
|
|
4667
|
+
try {
|
|
4668
|
+
return process.env.NODE_ENV !== "production";
|
|
4669
|
+
}
|
|
4670
|
+
catch {
|
|
4671
|
+
return false;
|
|
4672
|
+
}
|
|
4673
|
+
})();
|
|
4674
|
+
/**
|
|
4675
|
+
* Один раз на источник сообщает, что конфиг остался на устаревшей плоской форме.
|
|
4676
|
+
*
|
|
4677
|
+
* Без такого маркера момент «легаси закончилось» не наступает никогда, и временный слой
|
|
4678
|
+
* совместимости становится постоянным.
|
|
4679
|
+
*/
|
|
4680
|
+
const warnLegacyAxis = ({ dataSourceName, attributeName }) => {
|
|
4681
|
+
if (!isDevEnvironment)
|
|
4682
|
+
return;
|
|
4683
|
+
const key = `${dataSourceName ?? "?"}:${attributeName ?? "?"}`;
|
|
4684
|
+
if (warnedLegacySources.has(key))
|
|
4685
|
+
return;
|
|
4686
|
+
warnedLegacySources.add(key);
|
|
4687
|
+
// eslint-disable-next-line no-console
|
|
4688
|
+
console.warn(`[Dashboard] Источник "${key}" использует устаревшие поля оси (chartAxis/axisColor/hideAxis). ` +
|
|
4689
|
+
"Перепишите их в объект axis: { type, side, color, title, hide }. " +
|
|
4690
|
+
"Слой совместимости временный.");
|
|
4691
|
+
};
|
|
4692
|
+
/**
|
|
4693
|
+
* Настройки оси источника.
|
|
4694
|
+
*
|
|
4695
|
+
* Читает `axis`, а при его отсутствии собирает объект из устаревших плоских полей
|
|
4696
|
+
* `chartAxis` / `axisColor` / `hideAxis`. Заданный `axis` имеет приоритет: узел, который уже
|
|
4697
|
+
* правили в редакторе, не должен откатываться к старым значениям.
|
|
4698
|
+
*/
|
|
4699
|
+
const resolveAxis = (source) => {
|
|
4700
|
+
if (!source)
|
|
4701
|
+
return EMPTY_AXIS;
|
|
4702
|
+
const { axis, chartAxis, axisColor, hideAxis } = source;
|
|
4703
|
+
if (axis)
|
|
4704
|
+
return axis;
|
|
4705
|
+
if (chartAxis === undefined && axisColor === undefined && hideAxis === undefined)
|
|
4706
|
+
return EMPTY_AXIS;
|
|
4707
|
+
warnLegacyAxis(source);
|
|
4708
|
+
return {
|
|
4709
|
+
type: chartAxis === "x" ? "x" : "y",
|
|
4710
|
+
color: axisColor,
|
|
4711
|
+
hide: hideAxis,
|
|
4712
|
+
};
|
|
4713
|
+
};
|
|
4714
|
+
/**
|
|
4715
|
+
* Источник питает ось значений.
|
|
4716
|
+
*
|
|
4717
|
+
* Отсутствие `axis.type` означает `"y"`: конфиг без явного типа — самый частый случай,
|
|
4718
|
+
* и раньше такой источник молча выпадал из графика.
|
|
4719
|
+
*/
|
|
4720
|
+
const isValueAxis = (source) => (resolveAxis(source).type ?? "y") === "y";
|
|
4721
|
+
/** Сторона оси; отсутствие `axis.side` означает `"left"`. */
|
|
4722
|
+
const getAxisSide = (source) => resolveAxis(source).side ?? "left";
|
|
4723
|
+
/** Источник выводится на правой оси. */
|
|
4724
|
+
const isRightAxis = (source) => getAxisSide(source) === "right";
|
|
4725
|
+
/**
|
|
4726
|
+
* Запись описывает ось чарта, а не источник фильтра.
|
|
4727
|
+
*
|
|
4728
|
+
* `BarChartFilter` собирает `relatedConfig` вручную и осей не задаёт — ему нужна исходная палитра,
|
|
4729
|
+
* а не растянутая под число элементов.
|
|
4730
|
+
*/
|
|
4731
|
+
const hasAxisConfig = ({ axis, chartAxis }) => axis !== undefined || chartAxis !== undefined;
|
|
4732
|
+
|
|
4551
4733
|
const getAttributesConfiguration = (layer) => {
|
|
4552
4734
|
const layerAttributeConfiguration = layer?.configuration?.attributesConfiguration ?? {};
|
|
4553
4735
|
const { geometryAttribute, idAttribute } = layerAttributeConfiguration;
|
|
@@ -4572,7 +4754,7 @@ const getAttributesConfiguration = (layer) => {
|
|
|
4572
4754
|
|
|
4573
4755
|
const formatChartRelatedValue = (t, value, layerInfo, relatedAttributes) => {
|
|
4574
4756
|
const layerDefinition = getAttributesConfiguration(layerInfo);
|
|
4575
|
-
const relatedAxis = relatedAttributes.find(
|
|
4757
|
+
const relatedAxis = relatedAttributes.find(isValueAxis);
|
|
4576
4758
|
const attribute = getAttributeConfigurationByName(layerDefinition.attributes, relatedAxis?.attributeName);
|
|
4577
4759
|
return attribute
|
|
4578
4760
|
? formatAttributeValue({ t, type: attribute.type, value, stringFormat: attribute.stringFormat })
|
|
@@ -5417,11 +5599,11 @@ const getAttributeValue = (element, attributes) => {
|
|
|
5417
5599
|
return typeof value === "string" && maxLength && maxLength < value.length ? (jsx(TextTrim, { maxLength: maxLength, wordBreak: wordBreak, expandable: expandable, lineBreak: lineBreak, children: value })) : (value);
|
|
5418
5600
|
};
|
|
5419
5601
|
|
|
5420
|
-
const getChartAxes = (chartElement) => chartElement?.options?.relatedDataSources?.filter(
|
|
5602
|
+
const getChartAxes = (chartElement) => chartElement?.options?.relatedDataSources?.filter(isValueAxis);
|
|
5421
5603
|
|
|
5422
5604
|
const getChartFilterName = (relatedDataSources) => {
|
|
5423
5605
|
const relatedAttributes = relatedDataSources || [];
|
|
5424
|
-
const axes = relatedAttributes.filter(
|
|
5606
|
+
const axes = relatedAttributes.filter(isValueAxis);
|
|
5425
5607
|
return axes?.[0]?.filterName;
|
|
5426
5608
|
};
|
|
5427
5609
|
|
|
@@ -7051,6 +7233,96 @@ const useFetchImageWithAuth = (url) => {
|
|
|
7051
7233
|
return isExternal ? url : blobUrl;
|
|
7052
7234
|
};
|
|
7053
7235
|
|
|
7236
|
+
/**
|
|
7237
|
+
* Оси значений линейного графика и атрибуты, по `stringFormat` которых форматируются деления.
|
|
7238
|
+
*
|
|
7239
|
+
* У левой и правой осей это разные атрибуты, поэтому они резолвятся по отдельности: иначе на
|
|
7240
|
+
* правой оси окажутся единицы измерения левой.
|
|
7241
|
+
*/
|
|
7242
|
+
const useChartAxisAttributes = ({ dataSources, relatedAttributes }) => {
|
|
7243
|
+
const { layerInfos, dataSources: fetchedDataSources } = useWidgetContext();
|
|
7244
|
+
const axes = useMemo(() => (relatedAttributes || []).filter(isValueAxis), [relatedAttributes]);
|
|
7245
|
+
const strokeColors = useMemo(() => axes.map(related => resolveAxis(related).color), [axes]);
|
|
7246
|
+
const leftAxis = useMemo(() => axes.find(related => !isRightAxis(related)) ?? axes[0] ?? relatedAttributes?.[0], [axes, relatedAttributes]);
|
|
7247
|
+
const rightAxis = useMemo(() => axes.find(isRightAxis), [axes]);
|
|
7248
|
+
const resolveAxisAttribute = useCallback((related) => {
|
|
7249
|
+
if (!related)
|
|
7250
|
+
return undefined;
|
|
7251
|
+
const layerInfo = getDataSourceLayerInfo({
|
|
7252
|
+
layerInfos,
|
|
7253
|
+
configDataSource: dataSources?.find(({ name }) => name === related.dataSourceName),
|
|
7254
|
+
fetchedDataSource: getDataSource(related.dataSourceName, fetchedDataSources),
|
|
7255
|
+
});
|
|
7256
|
+
return getLayerInfoAttribute(layerInfo, related.attributeName);
|
|
7257
|
+
}, [dataSources, fetchedDataSources, layerInfos]);
|
|
7258
|
+
const leftAxisAttribute = useMemo(() => resolveAxisAttribute(leftAxis), [resolveAxisAttribute, leftAxis]);
|
|
7259
|
+
const rightAxisAttribute = useMemo(() => resolveAxisAttribute(rightAxis), [resolveAxisAttribute, rightAxis]);
|
|
7260
|
+
return { axes, strokeColors, leftAxisAttribute, rightAxisAttribute };
|
|
7261
|
+
};
|
|
7262
|
+
|
|
7263
|
+
/**
|
|
7264
|
+
* Форматтеры делений левой и правой шкал линейного графика — по `stringFormat` своего атрибута.
|
|
7265
|
+
*
|
|
7266
|
+
* Отдаются в `tickFormat` генератора оси, а не подменяют текст после отрисовки: d3 измеряет ширину
|
|
7267
|
+
* шкалы по уже нарисованным подписям и по ней сдвигает поле графика. Подмена текста задним числом
|
|
7268
|
+
* (`30` → `30,0`) делала подпись шире замера, и она заезжала на подпись оси слева.
|
|
7269
|
+
*/
|
|
7270
|
+
const useChartAxisTickFormat = ({ dataSources, relatedAttributes }) => {
|
|
7271
|
+
const { t } = useGlobalContext();
|
|
7272
|
+
const { leftAxisAttribute, rightAxisAttribute } = useChartAxisAttributes({ dataSources, relatedAttributes });
|
|
7273
|
+
const createTickFormat = useCallback((attribute) => (value) => {
|
|
7274
|
+
if (!value)
|
|
7275
|
+
return "0";
|
|
7276
|
+
return attribute
|
|
7277
|
+
? String(formatAttributeValue({
|
|
7278
|
+
t,
|
|
7279
|
+
type: attribute.type,
|
|
7280
|
+
value: Number(value),
|
|
7281
|
+
stringFormat: attribute.stringFormat,
|
|
7282
|
+
noUnits: true,
|
|
7283
|
+
}))
|
|
7284
|
+
: String(value);
|
|
7285
|
+
}, [t]);
|
|
7286
|
+
const formatLeftTick = useMemo(() => createTickFormat(leftAxisAttribute), [createTickFormat, leftAxisAttribute]);
|
|
7287
|
+
const formatRightTick = useMemo(() => createTickFormat(rightAxisAttribute), [createTickFormat, rightAxisAttribute]);
|
|
7288
|
+
return { formatLeftTick, formatRightTick };
|
|
7289
|
+
};
|
|
7290
|
+
|
|
7291
|
+
/**
|
|
7292
|
+
* Подписи осей линейного графика и место, которое они занимают над телом графика.
|
|
7293
|
+
*
|
|
7294
|
+
* Режим размещения общий для всех осей (`options.axis.titlePosition`), текст — у каждой оси свой.
|
|
7295
|
+
* Цвет подписи отдельной опцией не задаётся: одна серия на стороне — подпись в её цвет, несколько —
|
|
7296
|
+
* нейтральная, потому что тогда подпись описывает всю ось, а не одну из линий. Ширину вертикальных
|
|
7297
|
+
* подписей здесь не считаем — она зависит от числа строк текста и измеряется по факту.
|
|
7298
|
+
*/
|
|
7299
|
+
const useChartAxisTitles = ({ options, axes, isLineChart }) => {
|
|
7300
|
+
const axisTitlePosition = options?.axis?.titlePosition ?? "side";
|
|
7301
|
+
const axisTitles = useMemo(() => {
|
|
7302
|
+
const pick = (side) => {
|
|
7303
|
+
const sideAxes = axes.filter(related => getAxisSide(related) === side);
|
|
7304
|
+
const title = sideAxes.map(resolveAxis).find(axis => axis.title)?.title;
|
|
7305
|
+
if (!title)
|
|
7306
|
+
return undefined;
|
|
7307
|
+
return { title, color: sideAxes.length === 1 ? resolveAxis(sideAxes[0]).color : undefined };
|
|
7308
|
+
};
|
|
7309
|
+
return { left: pick("left"), right: pick("right") };
|
|
7310
|
+
}, [axes]);
|
|
7311
|
+
const hasAxisTitles = !!(isLineChart && (axisTitles.left || axisTitles.right));
|
|
7312
|
+
const hasTopTitles = hasAxisTitles && axisTitlePosition === "top";
|
|
7313
|
+
const hasSideTitles = hasAxisTitles && axisTitlePosition === "side";
|
|
7314
|
+
const hideLeftAxis = useMemo(() => axes.filter(related => !isRightAxis(related)).every(related => resolveAxis(related).hide), [axes]);
|
|
7315
|
+
const hideRightAxis = useMemo(() => axes.filter(isRightAxis).every(related => resolveAxis(related).hide), [axes]);
|
|
7316
|
+
return {
|
|
7317
|
+
axisTitles,
|
|
7318
|
+
hasTopTitles,
|
|
7319
|
+
hasSideTitles,
|
|
7320
|
+
axisTitlesHeight: hasTopTitles ? AXIS_TITLE_TOP_HEIGHT : 0,
|
|
7321
|
+
hideLeftAxis,
|
|
7322
|
+
hideRightAxis,
|
|
7323
|
+
};
|
|
7324
|
+
};
|
|
7325
|
+
|
|
7054
7326
|
const HEIGHT_OFFSET = 20;
|
|
7055
7327
|
const FILL_OPACITY = 0.28;
|
|
7056
7328
|
const lineGenerator = line()
|
|
@@ -7096,20 +7368,10 @@ function wrap() {
|
|
|
7096
7368
|
}
|
|
7097
7369
|
}
|
|
7098
7370
|
const useChartChange = ({ dataSources, chartId, width, height, relatedAttributes, defaultColor, fontColor, markers, showMarkers, }) => {
|
|
7099
|
-
const {
|
|
7100
|
-
|
|
7101
|
-
|
|
7102
|
-
|
|
7103
|
-
.map(({ axisColor }) => axisColor);
|
|
7104
|
-
const yAxis = useMemo(() => relatedAttributes?.find(({ chartAxis }) => chartAxis === "y") ?? relatedAttributes?.[0], [relatedAttributes]);
|
|
7105
|
-
const yAxisAttribute = useMemo(() => {
|
|
7106
|
-
const layerInfo = getDataSourceLayerInfo({
|
|
7107
|
-
layerInfos,
|
|
7108
|
-
configDataSource: dataSources?.find(({ name }) => name === yAxis?.dataSourceName),
|
|
7109
|
-
fetchedDataSource: getDataSource(yAxis?.dataSourceName, fetchedDataSources),
|
|
7110
|
-
});
|
|
7111
|
-
return getLayerInfoAttribute(layerInfo, yAxis?.attributeName);
|
|
7112
|
-
}, [dataSources, fetchedDataSources, layerInfos, yAxis]);
|
|
7371
|
+
const { strokeColors } = useChartAxisAttributes({
|
|
7372
|
+
dataSources,
|
|
7373
|
+
relatedAttributes,
|
|
7374
|
+
});
|
|
7113
7375
|
const ref = useRef({
|
|
7114
7376
|
path: null,
|
|
7115
7377
|
area: null,
|
|
@@ -7162,22 +7424,9 @@ const useChartChange = ({ dataSources, chartId, width, height, relatedAttributes
|
|
|
7162
7424
|
svg
|
|
7163
7425
|
.selectAll(`.${lineChartClassNames.lineChartXScaleGlobal} .tick text`)
|
|
7164
7426
|
.attr("y", 16);
|
|
7165
|
-
|
|
7166
|
-
|
|
7167
|
-
|
|
7168
|
-
if (!item)
|
|
7169
|
-
return 0;
|
|
7170
|
-
return yAxisAttribute
|
|
7171
|
-
? formatAttributeValue({
|
|
7172
|
-
t,
|
|
7173
|
-
type: yAxisAttribute.type,
|
|
7174
|
-
value: item,
|
|
7175
|
-
stringFormat: yAxisAttribute.stringFormat,
|
|
7176
|
-
noUnits: true,
|
|
7177
|
-
})
|
|
7178
|
-
: item;
|
|
7179
|
-
})
|
|
7180
|
-
.each(wrap);
|
|
7427
|
+
// Текст делений форматируется ещё в генераторе оси (useChartAxisTickFormat), до замера ширины
|
|
7428
|
+
// шкалы; здесь его только укорачиваем.
|
|
7429
|
+
svg.selectAll(`.${lineChartClassNames.lineChartYScaleGlobal} .tick text`).each(wrap);
|
|
7181
7430
|
svg.selectAll(".tick text").attr("style", `color: ${fontColor}`);
|
|
7182
7431
|
const global = svg.select(`.${lineChartClassNames.lineChartLinesGlobal}`);
|
|
7183
7432
|
const lineChartLines = svg.selectAll(`.${lineChartClassNames.lineChartLine}`);
|
|
@@ -7213,7 +7462,6 @@ const useChartChange = ({ dataSources, chartId, width, height, relatedAttributes
|
|
|
7213
7462
|
svg.append("defs").html(() => defs.join(""));
|
|
7214
7463
|
}, [
|
|
7215
7464
|
fontColor,
|
|
7216
|
-
yAxisAttribute,
|
|
7217
7465
|
chartId,
|
|
7218
7466
|
strokeColors,
|
|
7219
7467
|
defaultColor,
|
|
@@ -7221,7 +7469,6 @@ const useChartChange = ({ dataSources, chartId, width, height, relatedAttributes
|
|
|
7221
7469
|
onChange,
|
|
7222
7470
|
showMarkers,
|
|
7223
7471
|
markers,
|
|
7224
|
-
t,
|
|
7225
7472
|
]);
|
|
7226
7473
|
return [customize, onChange];
|
|
7227
7474
|
};
|
|
@@ -7378,10 +7625,10 @@ const useChartData = ({ element, type }) => {
|
|
|
7378
7625
|
const configDataSources = useConfigDataSources(type);
|
|
7379
7626
|
const relatedAttributes = useMemo(() => element?.options?.relatedDataSources || [], [element?.options?.relatedDataSources]);
|
|
7380
7627
|
const loading = useMemo(() => !!relatedAttributes?.length &&
|
|
7381
|
-
!dataSources?.some(({ name }) => relatedAttributes.some(
|
|
7628
|
+
!dataSources?.some(({ name }) => relatedAttributes.some(related => isValueAxis(related) && related.dataSourceName === name)), [dataSources, relatedAttributes]);
|
|
7382
7629
|
const fetchedData = useMemo(() => {
|
|
7383
7630
|
const isRelated = !!relatedAttributes?.length;
|
|
7384
|
-
const filteredAttributes = relatedAttributes.filter(
|
|
7631
|
+
const filteredAttributes = relatedAttributes.filter(isValueAxis);
|
|
7385
7632
|
if (!element)
|
|
7386
7633
|
return [];
|
|
7387
7634
|
if (isRelated) {
|
|
@@ -7389,7 +7636,7 @@ const useChartData = ({ element, type }) => {
|
|
|
7389
7636
|
return [];
|
|
7390
7637
|
return filteredAttributes
|
|
7391
7638
|
.map(relatedAxis => {
|
|
7392
|
-
const { dataSourceName,
|
|
7639
|
+
const { dataSourceName, attributeName, attributeUnits } = relatedAxis;
|
|
7393
7640
|
const dataSource = configDataSources.find(({ name }) => name === dataSourceName);
|
|
7394
7641
|
const featureDataSource = getDataSource(dataSourceName, dataSources);
|
|
7395
7642
|
const layerInfo = getDataSourceLayerInfo({
|
|
@@ -7409,7 +7656,10 @@ const useChartData = ({ element, type }) => {
|
|
|
7409
7656
|
layerInfo,
|
|
7410
7657
|
})
|
|
7411
7658
|
: null,
|
|
7412
|
-
color:
|
|
7659
|
+
color: resolveAxis(relatedAxis).color,
|
|
7660
|
+
// Сторона едет вместе с данными: серии без значений отсеиваются ниже, и сопоставлять
|
|
7661
|
+
// их с осями по индексу уже нельзя.
|
|
7662
|
+
axisSide: getAxisSide(relatedAxis),
|
|
7413
7663
|
attributeName,
|
|
7414
7664
|
attributeUnits,
|
|
7415
7665
|
dataSourceName,
|
|
@@ -7422,6 +7672,7 @@ const useChartData = ({ element, type }) => {
|
|
|
7422
7672
|
return [
|
|
7423
7673
|
{
|
|
7424
7674
|
items: getDataFromAttributes(t, element, attributes),
|
|
7675
|
+
axisSide: "left",
|
|
7425
7676
|
layerInfo: null,
|
|
7426
7677
|
attributeName: null,
|
|
7427
7678
|
attributeUnits: null,
|
|
@@ -7441,7 +7692,7 @@ const useChartData = ({ element, type }) => {
|
|
|
7441
7692
|
]);
|
|
7442
7693
|
const isResolved = useMemo(() => !relatedAttributes?.length ||
|
|
7443
7694
|
relatedAttributes
|
|
7444
|
-
.filter(
|
|
7695
|
+
.filter(isValueAxis)
|
|
7445
7696
|
.every(({ dataSourceName }) => Array.isArray(getDataSource(dataSourceName, dataSources)?.features)), [relatedAttributes, dataSources]);
|
|
7446
7697
|
const [data, setData] = useState(fetchedData);
|
|
7447
7698
|
useEffect(() => {
|
|
@@ -8973,6 +9224,15 @@ const ChartLegendContainer = styled(Flex).withConfig({ displayName: "ChartLegend
|
|
|
8973
9224
|
flex-direction: column;
|
|
8974
9225
|
flex-wrap: wrap;
|
|
8975
9226
|
justify-content: ${({ twoColumns }) => (twoColumns ? "flex-start" : "center")};
|
|
9227
|
+
|
|
9228
|
+
/* Явная опция column перебивает раскладку, которую легенде навязывает ChartContainer
|
|
9229
|
+
(под графиком — в ряд, сбоку — столбиком). Без опции поведение прежнее. */
|
|
9230
|
+
${({ $column }) => $column !== undefined &&
|
|
9231
|
+
css `
|
|
9232
|
+
&&& {
|
|
9233
|
+
flex-direction: ${$column ? "column" : "row"};
|
|
9234
|
+
}
|
|
9235
|
+
`}
|
|
8976
9236
|
`;
|
|
8977
9237
|
const ChartLegendItem = styled(Flex).withConfig({ displayName: "ChartLegendItem", componentId: "sc-16m9piw" }) `
|
|
8978
9238
|
cursor: ${({ onClick }) => (onClick ? "pointer" : "default")};
|
|
@@ -9041,12 +9301,129 @@ const ContainerChart = styled(Flex).withConfig({ displayName: "ContainerChart",
|
|
|
9041
9301
|
`}
|
|
9042
9302
|
`;
|
|
9043
9303
|
const ContainerLegend = styled(Flex).withConfig({ displayName: "ContainerLegend", componentId: "sc-z1n1s8" }) ``;
|
|
9044
|
-
|
|
9304
|
+
/**
|
|
9305
|
+
* Выравнивание строки по полю графика: ширина тела графика, а внутренние отступы — до краёв поля
|
|
9306
|
+
* (колонка подписи оси и значения шкалы). Тело графика центрируется в слоте, поэтому и строка
|
|
9307
|
+
* центрируется. Правило поднято `&&&` над шириной, которую строкам задаёт `ContainerValue`.
|
|
9308
|
+
*/
|
|
9309
|
+
const plotInsetsMixin = css `
|
|
9310
|
+
${({ $insets }) => $insets &&
|
|
9311
|
+
css `
|
|
9312
|
+
&&& {
|
|
9313
|
+
box-sizing: border-box;
|
|
9314
|
+
align-self: center;
|
|
9315
|
+
width: ${$insets.width}px;
|
|
9316
|
+
max-width: 100%;
|
|
9317
|
+
padding-left: ${$insets.left}px;
|
|
9318
|
+
padding-right: ${$insets.right}px;
|
|
9319
|
+
}
|
|
9320
|
+
`}
|
|
9321
|
+
`;
|
|
9322
|
+
/**
|
|
9323
|
+
* Строка ждёт, пока график сообщит положение поля: место занимает, но не видна. Иначе до первой
|
|
9324
|
+
* отрисовки d3 она стояла бы по краю контейнера и потом прыгала на место.
|
|
9325
|
+
*/
|
|
9326
|
+
const awaitingPlotMixin = css `
|
|
9327
|
+
${({ $awaitingPlot }) => $awaitingPlot &&
|
|
9328
|
+
css `
|
|
9329
|
+
visibility: hidden;
|
|
9330
|
+
`}
|
|
9331
|
+
`;
|
|
9332
|
+
/**
|
|
9333
|
+
* Строка под телом графика: подпись оси X и, при `legendInline`, легенда справа от неё.
|
|
9334
|
+
*
|
|
9335
|
+
* `$offsetTop` подтягивает строку к подписям оси X: под ними внутри SVG остаётся пустая полоса,
|
|
9336
|
+
* и без поправки зазор получился бы втрое больше макетного.
|
|
9337
|
+
*/
|
|
9338
|
+
const ChartFooter = styled(Flex).withConfig({ displayName: "ChartFooter", componentId: "sc-nii28w" }) `
|
|
9339
|
+
align-items: center;
|
|
9340
|
+
flex-wrap: nowrap;
|
|
9341
|
+
gap: 0.5rem;
|
|
9342
|
+
width: 100%;
|
|
9343
|
+
margin-top: ${({ $offsetTop }) => $offsetTop ?? 0}px;
|
|
9344
|
+
justify-content: ${({ $align }) => $align};
|
|
9345
|
+
|
|
9346
|
+
${ContainerLegend} {
|
|
9347
|
+
justify-content: flex-end;
|
|
9348
|
+
margin-left: auto;
|
|
9349
|
+
}
|
|
9350
|
+
|
|
9351
|
+
/* Легенда в строке с подписью: записи прижаты вправо, без отступа сверху, который ей задаёт
|
|
9352
|
+
ContainerValue, и без нижнего отступа записей — иначе она съедет вниз относительно подписи.
|
|
9353
|
+
Прижимать нужно сами записи: обёртки легенды — Flex из uilib-gl с width: 100%, и выравнивание
|
|
9354
|
+
внешнего контейнера до записей не доходит, а своё у легенды — по центру. */
|
|
9355
|
+
&&& ${ChartLegendContainer} {
|
|
9356
|
+
justify-content: flex-end;
|
|
9357
|
+
margin-top: 0;
|
|
9358
|
+
}
|
|
9359
|
+
|
|
9360
|
+
&&& ${ChartLegendItem} {
|
|
9361
|
+
margin-bottom: 0;
|
|
9362
|
+
}
|
|
9363
|
+
|
|
9364
|
+
${plotInsetsMixin};
|
|
9365
|
+
${awaitingPlotMixin};
|
|
9366
|
+
`;
|
|
9367
|
+
const ChartXAxisTitle = styled.div.withConfig({ displayName: "ChartXAxisTitle", componentId: "sc-1vsgzi9" }) `
|
|
9368
|
+
font-size: 0.625rem;
|
|
9369
|
+
line-height: 0.75rem;
|
|
9370
|
+
white-space: nowrap;
|
|
9371
|
+
color: ${({ $color, theme: { palette } }) => $color || palette.textDisabled};
|
|
9372
|
+
`;
|
|
9373
|
+
/**
|
|
9374
|
+
* Строка легенды под графиком. `$gapTop` заменяет отступ сверху, который легенде задаёт `ContainerValue`;
|
|
9375
|
+
* `$offsetTop` сдвигает саму строку — подтягивает её к подписям оси X, как строку с подписью оси.
|
|
9376
|
+
*
|
|
9377
|
+
* `$justify` выравнивает сами записи. Выравнивание строки (`justifyContent`) до них не доходит: обёртки
|
|
9378
|
+
* легенды — Flex из uilib-gl с `width: 100%`, а записи внутри легенда всегда центрирует.
|
|
9379
|
+
*/
|
|
9380
|
+
const ChartLegendRow = styled(ContainerLegend).withConfig({ displayName: "ChartLegendRow", componentId: "sc-1a12wrz" }) `
|
|
9381
|
+
${({ $offsetTop }) => $offsetTop !== undefined &&
|
|
9382
|
+
css `
|
|
9383
|
+
margin-top: ${$offsetTop}px;
|
|
9384
|
+
`}
|
|
9385
|
+
|
|
9386
|
+
${({ $gapTop }) => $gapTop !== undefined &&
|
|
9387
|
+
css `
|
|
9388
|
+
&&& ${ChartLegendContainer} {
|
|
9389
|
+
margin-top: ${$gapTop}px;
|
|
9390
|
+
}
|
|
9391
|
+
`}
|
|
9392
|
+
|
|
9393
|
+
${({ $justify }) => $justify &&
|
|
9394
|
+
css `
|
|
9395
|
+
&&& ${ChartLegendContainer} {
|
|
9396
|
+
justify-content: ${$justify};
|
|
9397
|
+
}
|
|
9398
|
+
`}
|
|
9399
|
+
|
|
9400
|
+
${plotInsetsMixin};
|
|
9401
|
+
${awaitingPlotMixin};
|
|
9402
|
+
`;
|
|
9403
|
+
/**
|
|
9404
|
+
* Колонка «график + подпись оси X» для легенды сбоку (`twoColumns`). Без неё подпись встала бы третьим
|
|
9405
|
+
* элементом ряда рядом с легендой, а не под графиком.
|
|
9406
|
+
*/
|
|
9407
|
+
const ChartWithFooter = styled(Flex).withConfig({ displayName: "ChartWithFooter", componentId: "sc-140gv2s" }) `
|
|
9408
|
+
flex-direction: column;
|
|
9409
|
+
flex-wrap: nowrap;
|
|
9410
|
+
min-width: 0;
|
|
9411
|
+
|
|
9412
|
+
${({ $fill }) => $fill &&
|
|
9413
|
+
css `
|
|
9414
|
+
min-height: 0;
|
|
9415
|
+
`}
|
|
9416
|
+
|
|
9417
|
+
&&& ${ContainerChart} {
|
|
9418
|
+
width: 100%;
|
|
9419
|
+
}
|
|
9420
|
+
`;
|
|
9421
|
+
const ContainerUnits = styled.div.withConfig({ displayName: "ContainerUnits", componentId: "sc-vj15z6" }) `
|
|
9045
9422
|
margin-left: 0.5rem;
|
|
9046
9423
|
white-space: nowrap;
|
|
9047
9424
|
font-size: 0.75rem;
|
|
9048
9425
|
`;
|
|
9049
|
-
const ContainerValue = styled(Flex).withConfig({ displayName: "ContainerValue", componentId: "sc-
|
|
9426
|
+
const ContainerValue = styled(Flex).withConfig({ displayName: "ContainerValue", componentId: "sc-1bnfj5v" }) `
|
|
9050
9427
|
justify-content: flex-end;
|
|
9051
9428
|
align-items: center;
|
|
9052
9429
|
flex-wrap: nowrap;
|
|
@@ -9065,7 +9442,7 @@ const ContainerValue = styled(Flex).withConfig({ displayName: "ContainerValue",
|
|
|
9065
9442
|
width: ${({ column }) => (column ? "100%" : "auto")};
|
|
9066
9443
|
}
|
|
9067
9444
|
|
|
9068
|
-
${ContainerChart}, ${ContainerLegend} {
|
|
9445
|
+
${ContainerChart}, ${ContainerLegend}, ${ChartWithFooter} {
|
|
9069
9446
|
width: ${({ column }) => (column ? "100%" : "50%")};
|
|
9070
9447
|
}
|
|
9071
9448
|
|
|
@@ -9088,7 +9465,7 @@ const SizeIconMixin = css `
|
|
|
9088
9465
|
font-size: ${({ $fontSize }) => $fontSize}px !important;
|
|
9089
9466
|
}
|
|
9090
9467
|
`;
|
|
9091
|
-
styled(Icon).withConfig({ displayName: "ContainerIcon", componentId: "sc-
|
|
9468
|
+
styled(Icon).withConfig({ displayName: "ContainerIcon", componentId: "sc-18399bz" }) `
|
|
9092
9469
|
width: auto;
|
|
9093
9470
|
height: auto;
|
|
9094
9471
|
margin-bottom: 0.5rem;
|
|
@@ -9102,7 +9479,7 @@ const SvgContainerColorMixin$1 = css `
|
|
|
9102
9479
|
fill: ${({ $fontColor }) => $fontColor};
|
|
9103
9480
|
}
|
|
9104
9481
|
`;
|
|
9105
|
-
const SvgContainer$1 = styled.div.withConfig({ displayName: "SvgContainer", componentId: "sc-
|
|
9482
|
+
const SvgContainer$1 = styled.div.withConfig({ displayName: "SvgContainer", componentId: "sc-8l0ajh" }) `
|
|
9106
9483
|
&&& {
|
|
9107
9484
|
min-width: ${({ $width }) => ($width ? `${$width}px` : "1rem")};
|
|
9108
9485
|
max-width: ${({ $width }) => ($width ? `${$width}px` : "1rem")};
|
|
@@ -9114,7 +9491,7 @@ const SvgContainer$1 = styled.div.withConfig({ displayName: "SvgContainer", comp
|
|
|
9114
9491
|
}
|
|
9115
9492
|
}
|
|
9116
9493
|
`;
|
|
9117
|
-
const TwoColumnContainerWrapper = styled(Container).withConfig({ displayName: "TwoColumnContainerWrapper", componentId: "sc-
|
|
9494
|
+
const TwoColumnContainerWrapper = styled(Container).withConfig({ displayName: "TwoColumnContainerWrapper", componentId: "sc-1yxeknf" }) `
|
|
9118
9495
|
flex-direction: row;
|
|
9119
9496
|
flex-wrap: nowrap;
|
|
9120
9497
|
align-items: center;
|
|
@@ -9141,6 +9518,16 @@ const CameraContainer = memo(({ elementConfig, type, renderElement }) => {
|
|
|
9141
9518
|
return (jsxs(ContainerRoot, { ...root, children: [jsx(ContainerBackground, { elementConfig: elementConfig, renderElement: renderElement }), jsx(ExpandableTitle, { elementConfig: elementConfig, type: type, renderElement: renderElement }), isVisible && (jsxs(Container, { ...body, children: [jsx(ContainerAlias, { hasBottomMargin: true, children: renderElement({ id: "alias" }) }), jsx(ContainerValue, { children: renderElement({ id: "value", wrap: false }) })] }))] }));
|
|
9142
9519
|
});
|
|
9143
9520
|
|
|
9521
|
+
/**
|
|
9522
|
+
* Контекст, через который элемент `chart` сообщает контейнеру, где лежит поле графика.
|
|
9523
|
+
*
|
|
9524
|
+
* По макету подпись оси X и легенда выравниваются по полю графика, а не по краям контейнера.
|
|
9525
|
+
* Ширину шкал d3 вычисляет только при отрисовке, а подвал с подписью и легендой рисует
|
|
9526
|
+
* `ChartContainer` — снаружи элемента. Без контейнера (элемент сам по себе) провайдера нет,
|
|
9527
|
+
* и отчёт просто не отправляется.
|
|
9528
|
+
*/
|
|
9529
|
+
const ChartPlotContext = createContext({});
|
|
9530
|
+
|
|
9144
9531
|
/**
|
|
9145
9532
|
* Контекст вписывания графика (`options.fill` контейнера Chart).
|
|
9146
9533
|
*
|
|
@@ -9150,14 +9537,40 @@ const CameraContainer = memo(({ elementConfig, type, renderElement }) => {
|
|
|
9150
9537
|
*/
|
|
9151
9538
|
const FillContext = createContext({ fill: false, fitHeight: false });
|
|
9152
9539
|
|
|
9540
|
+
const isSameInsets = (prev, next) => !!prev && prev.left === next.left && prev.right === next.right && prev.width === next.width;
|
|
9153
9541
|
const ChartContainer = memo(({ elementConfig, isVisible, type, renderElement }) => {
|
|
9154
9542
|
const { options, children } = elementConfig || {};
|
|
9155
|
-
const { twoColumns, hideEmpty, height } = options || {};
|
|
9543
|
+
const { twoColumns, hideEmpty, height, legendInline } = options || {};
|
|
9156
9544
|
const fill = options?.fill;
|
|
9157
9545
|
const fillContextValue = useMemo(() => ({ fill: !!fill, fitHeight: !!fill && height != null }), [fill, height]);
|
|
9546
|
+
// Поле графика отчитывается после каждой отрисовки d3; одинаковые значения не пишем в стейт,
|
|
9547
|
+
// иначе отчёт и ре-рендер гоняли бы друг друга.
|
|
9548
|
+
const [plotInsets, setPlotInsets] = useState(null);
|
|
9549
|
+
const reportPlotInsets = useCallback((next) => setPlotInsets(prev => (isSameInsets(prev, next) ? prev : next)), []);
|
|
9550
|
+
const plotContextValue = useMemo(() => ({ reportPlotInsets }), [reportPlotInsets]);
|
|
9158
9551
|
const aliasElement = children.find(child => child.id === "alias");
|
|
9159
9552
|
const chartElement = children.find(child => child.id === "chart");
|
|
9160
9553
|
const legendElement = children.find(child => child.id === "legend");
|
|
9554
|
+
const isLineChart = chartElement?.options?.chartType === "line";
|
|
9555
|
+
const xAxisTitle = chartElement?.options?.axis?.x?.title;
|
|
9556
|
+
const footerJustify = useMemo(() => CHART_AXIS_ALIGN_JUSTIFY[chartElement?.options?.axis?.x?.align ?? "center"], [chartElement?.options?.axis?.x?.align]);
|
|
9557
|
+
// Легенда встаёт в строку с подписью оси X только когда та есть и легенда не вынесена вбок.
|
|
9558
|
+
const isLegendInline = useMemo(() => !!legendInline && !twoColumns && !!xAxisTitle, [legendInline, twoColumns, xAxisTitle]);
|
|
9559
|
+
// По макету подпись оси X и легенда у линейного графика выравниваются по полю графика, а не по
|
|
9560
|
+
// контейнеру. Легенда сбоку (twoColumns) живёт в своей колонке и в выравнивании не участвует.
|
|
9561
|
+
const footerInsets = useMemo(() => (isLineChart ? plotInsets : null), [isLineChart, plotInsets]);
|
|
9562
|
+
const isPlotLegend = isLineChart && !twoColumns;
|
|
9563
|
+
// Положение поля становится известно только после отрисовки: LineChart рисует d3 в useEffect, уже
|
|
9564
|
+
// после первого кадра. До отчёта подвал встал бы по краю контейнера и затем прыгнул на место, поэтому
|
|
9565
|
+
// прячем его — место под ним сохраняется, а появляется он вместе с линиями графика.
|
|
9566
|
+
const isAwaitingPlot = isLineChart && !plotInsets;
|
|
9567
|
+
// Пока подпись оси X не задана, легенда выравнивается прежней опцией `center` (по умолчанию — к левой
|
|
9568
|
+
// границе поля графика); с подписью — по ней, иначе подпись и легенда разъезжаются по разным краям.
|
|
9569
|
+
const legendJustify = useMemo(() => {
|
|
9570
|
+
if (xAxisTitle)
|
|
9571
|
+
return footerJustify;
|
|
9572
|
+
return legendElement?.options?.center ? "center" : "flex-start";
|
|
9573
|
+
}, [xAxisTitle, footerJustify, legendElement?.options?.center]);
|
|
9161
9574
|
const { root, body } = useContainerRoot({ elementConfig });
|
|
9162
9575
|
const { data, loading } = useChartData({
|
|
9163
9576
|
element: chartElement,
|
|
@@ -9169,7 +9582,12 @@ const ChartContainer = memo(({ elementConfig, isVisible, type, renderElement })
|
|
|
9169
9582
|
const hasItems = !!data[0]?.items?.length;
|
|
9170
9583
|
if (!loading && !hasItems && hideEmpty)
|
|
9171
9584
|
return null;
|
|
9172
|
-
|
|
9585
|
+
const chartSlot = (jsx(ContainerChart, { "$fill": !!fill, children: jsx(FillContext.Provider, { value: fillContextValue, children: jsx(ChartPlotContext.Provider, { value: plotContextValue, children: renderElement({ id: "chart" }) }) }) }));
|
|
9586
|
+
const footer = xAxisTitle ? (jsxs(ChartFooter, { "$align": footerJustify, "$insets": footerInsets, "$offsetTop": isLineChart ? X_AXIS_TITLE_GAP - LINE_CHART_X_LABELS_BLANK : 0, "$awaitingPlot": isAwaitingPlot, children: [jsx(ChartXAxisTitle, { children: xAxisTitle }), isLegendInline && jsx(ContainerLegend, { children: renderElement({ id: "legend" }) })] })) : null;
|
|
9587
|
+
// Легенда линейного графика: под подписью оси X — через X_AXIS_TITLE_LEGEND_GAP, без подписи — на её
|
|
9588
|
+
// месте, вплотную под подписями делений оси X. У остальных графиков — прежняя раскладка общей легенды.
|
|
9589
|
+
const legendRow = isLegendInline ? null : (jsx(ChartLegendRow, { justifyContent: legendJustify, "$insets": isPlotLegend ? footerInsets : null, "$gapTop": isPlotLegend ? (xAxisTitle ? X_AXIS_TITLE_LEGEND_GAP : 0) : undefined, "$offsetTop": isPlotLegend && !xAxisTitle ? X_AXIS_TITLE_GAP - LINE_CHART_X_LABELS_BLANK : undefined, "$justify": isPlotLegend ? legendJustify : undefined, "$awaitingPlot": isPlotLegend && isAwaitingPlot, children: renderElement({ id: "legend" }) }));
|
|
9590
|
+
return (jsxs(ContainerRoot, { ...root, children: [jsx(ContainerBackground, { elementConfig: elementConfig, renderElement: renderElement }), jsx(ExpandableTitle, { elementConfig: elementConfig, type: type, renderElement: renderElement }), isVisible && (jsxs(Container, { ...body, isColumn: true, children: [aliasElement && jsx(ContainerAlias, { hasBottomMargin: true, children: renderElement({ id: "alias" }) }), jsx(ContainerValue, { column: !twoColumns, alignItems: twoColumns && fill ? "stretch" : "center", "$fill": !!fill, children: hasItems ? (jsxs(Fragment$1, { children: [twoColumns && footer ? (jsxs(ChartWithFooter, { "$fill": !!fill, children: [chartSlot, footer] })) : (jsxs(Fragment$1, { children: [chartSlot, footer] })), legendRow] })) : (jsx(Fragment$1, { children: "\u2014" })) })] }))] }));
|
|
9173
9591
|
});
|
|
9174
9592
|
|
|
9175
9593
|
const InnerContainerWrapper = styled.div.withConfig({ displayName: "InnerContainerWrapper", componentId: "sc-1a1fl7q" }) `
|
|
@@ -9527,6 +9945,7 @@ const DEFAULT_BAR_CHART_HEIGHT = 100;
|
|
|
9527
9945
|
const BAR_CHART_HEADER_HEIGHT = 40;
|
|
9528
9946
|
const BAR_CHART_FOOTER_MARGIN = 16;
|
|
9529
9947
|
const LINE_CHART_LABEL_MARGIN = 20;
|
|
9948
|
+
const LINE_CHART_X_AXIS_PADDING = 15;
|
|
9530
9949
|
const DEFAULT_BAR_CHART_MARGINS = {
|
|
9531
9950
|
top: 0,
|
|
9532
9951
|
left: 0,
|
|
@@ -15190,9 +15609,9 @@ const ElementImage = memo(({ type, elementConfig }) => {
|
|
|
15190
15609
|
});
|
|
15191
15610
|
|
|
15192
15611
|
const ElementLegend = memo(({ type, element, elementConfig }) => {
|
|
15193
|
-
const { attributes,
|
|
15612
|
+
const { attributes, expandedContainers } = useWidgetContext(type);
|
|
15194
15613
|
const { options } = elementConfig || {};
|
|
15195
|
-
const { twoColumns, chartId, relatedDataSources, fontSize } = options || {};
|
|
15614
|
+
const { twoColumns, column, chartId, relatedDataSources, fontSize } = options || {};
|
|
15196
15615
|
const chartElement = useMemo(() => returnFound(element?.children, { id: chartId }), [chartId, element?.children]);
|
|
15197
15616
|
const { data, loading } = useChartData({
|
|
15198
15617
|
element: chartElement,
|
|
@@ -15203,10 +15622,10 @@ const ElementLegend = memo(({ type, element, elementConfig }) => {
|
|
|
15203
15622
|
if (!data[0]?.items?.length)
|
|
15204
15623
|
return [];
|
|
15205
15624
|
if (chartElement?.options?.chartType === "line") {
|
|
15206
|
-
return axes.map(
|
|
15625
|
+
return axes.map(related => {
|
|
15207
15626
|
return {
|
|
15208
|
-
name: alias,
|
|
15209
|
-
color:
|
|
15627
|
+
name: related.alias,
|
|
15628
|
+
color: resolveAxis(related).color,
|
|
15210
15629
|
};
|
|
15211
15630
|
});
|
|
15212
15631
|
}
|
|
@@ -15220,7 +15639,7 @@ const ElementLegend = memo(({ type, element, elementConfig }) => {
|
|
|
15220
15639
|
});
|
|
15221
15640
|
}, [data, chartElement?.options?.chartType, relatedDataSources, axes, attributes]);
|
|
15222
15641
|
return !chartElement?.options?.expanded ||
|
|
15223
|
-
expandedContainers?.[chartElement.id] ? (jsx(ChartLegend, { data: legendData, loading: loading, chartElement: chartElement, twoColumns: twoColumns, fontSize: fontSize, type: type })) : null;
|
|
15642
|
+
expandedContainers?.[chartElement.id] ? (jsx(ChartLegend, { data: legendData, loading: loading, chartElement: chartElement, twoColumns: twoColumns, column: column, fontSize: fontSize, type: type })) : null;
|
|
15224
15643
|
});
|
|
15225
15644
|
|
|
15226
15645
|
const ExternalLink = styled(IconButton).attrs(() => ({
|
|
@@ -16788,7 +17207,11 @@ const getDataFromRelatedFeatures = ({ t, config, filters, relatedConfig, dataSou
|
|
|
16788
17207
|
if (isOtherSliced) {
|
|
16789
17208
|
data = data.slice(0, config?.options?.otherItems);
|
|
16790
17209
|
}
|
|
16791
|
-
|
|
17210
|
+
// Источник чарта отличается от источника фильтра наличием осей: BarChartFilter собирает
|
|
17211
|
+
// relatedConfig вручную и оси не задаёт, потому что ему нужна исходная палитра, а не растянутая
|
|
17212
|
+
// под число элементов. Гейт смотрит и на устаревший chartAxis — иначе у старых конфигов
|
|
17213
|
+
// молча поехали бы цвета столбцов и долей.
|
|
17214
|
+
const gradientArray = hasAxisConfig(relatedConfig)
|
|
16792
17215
|
? stretchPalette(colors, data.length)
|
|
16793
17216
|
: colors;
|
|
16794
17217
|
const filter = getConfigFilter(relatedConfig?.filterName, filters);
|
|
@@ -18854,6 +19277,15 @@ const StackBar = ({ data, filterName, type, alias, options, fill, renderElement,
|
|
|
18854
19277
|
return (jsxs(Fragment$1, { children: [(alias || showTotal) && (jsxs(StackBarHeader, { children: [jsx(StackBarAlias, { children: renderElement({ id: "alias" }) }), showTotal && (jsxs(StackBarTotal, { children: [jsx(StackBarValue, { children: formatValue(total) }), !!units && jsx(StackBarUnits, { children: units })] }))] })), groupTooltip ? (jsx(Tooltip$1, { placement: "top", arrow: true, content: renderGroupTooltip, children: ref => (jsx(StackBarContainer, { ref: ref, "$fill": fill, children: renderItems })) })) : (jsx(StackBarContainer, { "$fill": fill, children: renderItems }))] }));
|
|
18855
19278
|
};
|
|
18856
19279
|
|
|
19280
|
+
/** Горизонтальные подписи осей над телом графика: левая прижата влево, правая — вправо. */
|
|
19281
|
+
const AxisTitlesTop = ({ left, right, neutralColor }) => (jsxs(AxisTitlesRow, { children: [jsx(AxisTitleTop, { "$color": left?.color || neutralColor, title: left?.title, children: left?.title }), jsx(AxisTitleTop, { "$color": right?.color || neutralColor, title: right?.title, children: right?.title })] }));
|
|
19282
|
+
/** Вертикальная подпись оси сбоку от тела графика. Без подписи ничего не рендерит. */
|
|
19283
|
+
const AxisTitleSideSlot = ({ side, axisTitle, neutralColor, plotTop, plotBottom, }) => {
|
|
19284
|
+
if (!axisTitle)
|
|
19285
|
+
return null;
|
|
19286
|
+
return (jsx(AxisTitleSideColumn, { "$side": side, "$plotTop": plotTop, "$plotBottom": plotBottom, children: jsx(AxisTitleSide, { "$side": side, "$color": axisTitle.color || neutralColor, title: axisTitle.title, children: axisTitle.title }) }));
|
|
19287
|
+
};
|
|
19288
|
+
|
|
18857
19289
|
const Chart = memo(({ config, element, elementConfig, type, renderElement }) => {
|
|
18858
19290
|
const theme = useTheme();
|
|
18859
19291
|
const { palette } = theme;
|
|
@@ -18874,12 +19306,18 @@ const Chart = memo(({ config, element, elementConfig, type, renderElement }) =>
|
|
|
18874
19306
|
const radius = options?.radius || DEFAULT_BARCHART_RADIUS;
|
|
18875
19307
|
const padding = options?.padding || DEFAULT_BAR_PADDING;
|
|
18876
19308
|
const fontColor = options?.fontColor || palette.iconDisabled;
|
|
19309
|
+
// Нейтральная подпись оси — тем же цветом, что и значения шкалы (на макете у них один стиль).
|
|
19310
|
+
const axisTitleColor = options?.fontColor || palette.textDisabled;
|
|
18877
19311
|
const angle = options?.angle || DEFAULT_CHART_ANGLE;
|
|
18878
19312
|
const barWidth = options?.barWidth || DEFAULT_BAR_WIDTH;
|
|
18879
19313
|
const cornerRadius = options?.cornerRadius || 0;
|
|
18880
19314
|
const relatedAttributes = useMemo(() => relatedDataSources || [], [relatedDataSources]);
|
|
18881
|
-
const axes = useMemo(() => relatedAttributes.filter(
|
|
19315
|
+
const axes = useMemo(() => relatedAttributes.filter(isValueAxis), [relatedAttributes]);
|
|
18882
19316
|
const filterName = getChartFilterName(relatedDataSources);
|
|
19317
|
+
const { axisTitles, hasTopTitles, hasSideTitles, axisTitlesHeight, hideLeftAxis, hideRightAxis, } = useChartAxisTitles({ options, axes, isLineChart });
|
|
19318
|
+
// Ширина вертикальных подписей зависит от числа строк текста, поэтому тело между ними меряем
|
|
19319
|
+
// по факту, а не вычитаем константу.
|
|
19320
|
+
const [lineBodyRef, { width: measuredBodyWidth }] = useResizeBox(hasSideTitles);
|
|
18883
19321
|
const isRelated = !!relatedAttributes?.length;
|
|
18884
19322
|
const { data, loading } = useChartData({ element, type });
|
|
18885
19323
|
const totalWidthFromBarWidth = (data[0]?.items?.length || 0) * (barWidth + padding);
|
|
@@ -18907,17 +19345,54 @@ const Chart = memo(({ config, element, elementConfig, type, renderElement }) =>
|
|
|
18907
19345
|
const chartHeight = useMemo(() => (fitsHeight && measuredHeight ? measuredHeight : height), [fitsHeight, measuredHeight, height]);
|
|
18908
19346
|
// Круглый график вписываем по короткой стороне (object-fit: contain), центрируя в ячейке.
|
|
18909
19347
|
const pieSide = useMemo(() => (fitsHeight && measuredHeight ? Math.min(chartWidth, measuredHeight) : chartWidth), [fitsHeight, measuredHeight, chartWidth]);
|
|
19348
|
+
// Тело линейного графика — это ячейка за вычетом подписей осей. По высоте вычитаем только в
|
|
19349
|
+
// fill: вне fill chartHeight означает высоту самого тела, и обёртка честно растёт на подписи.
|
|
19350
|
+
const lineBodyWidth = useMemo(() => {
|
|
19351
|
+
if (!hasSideTitles)
|
|
19352
|
+
return chartWidth;
|
|
19353
|
+
if (measuredBodyWidth)
|
|
19354
|
+
return measuredBodyWidth;
|
|
19355
|
+
// До первого замера — оценка: одна строка текста и зазор на каждую подпись.
|
|
19356
|
+
const sideTitlesCount = Number(!!axisTitles.left) + Number(!!axisTitles.right);
|
|
19357
|
+
return Math.max(chartWidth - sideTitlesCount * (AXIS_TITLE_LINE_HEIGHT + AXIS_TITLE_GAP), 0);
|
|
19358
|
+
}, [hasSideTitles, measuredBodyWidth, chartWidth, axisTitles]);
|
|
19359
|
+
const lineBodyHeight = useMemo(() => (fitsHeight ? Math.max(chartHeight - axisTitlesHeight, 0) : chartHeight), [fitsHeight, chartHeight, axisTitlesHeight]);
|
|
19360
|
+
// Обёртка выше тела на строку горизонтальных подписей. В fill вся высота уже отмерена ячейкой,
|
|
19361
|
+
// поэтому прибавлять нечего — иначе тело вылезло бы за нижнюю границу.
|
|
19362
|
+
const lineWrapperHeight = useMemo(() => (fitsHeight ? chartHeight : chartHeight + axisTitlesHeight), [fitsHeight, chartHeight, axisTitlesHeight]);
|
|
18910
19363
|
const [customize] = useChartChange({
|
|
18911
19364
|
dataSources: config.dataSources,
|
|
18912
19365
|
chartId: elementConfig?.id,
|
|
18913
|
-
width:
|
|
18914
|
-
height:
|
|
19366
|
+
width: lineBodyWidth,
|
|
19367
|
+
height: lineBodyHeight,
|
|
18915
19368
|
fontColor,
|
|
18916
19369
|
relatedAttributes,
|
|
18917
19370
|
defaultColor: primaryColor,
|
|
18918
19371
|
markers: configMarkers,
|
|
18919
19372
|
showMarkers,
|
|
18920
19373
|
});
|
|
19374
|
+
const { formatLeftTick, formatRightTick } = useChartAxisTickFormat({
|
|
19375
|
+
dataSources: config.dataSources,
|
|
19376
|
+
relatedAttributes,
|
|
19377
|
+
});
|
|
19378
|
+
const { reportPlotInsets } = useContext(ChartPlotContext);
|
|
19379
|
+
// Положение поля графика известно только после отрисовки: ширину шкал вычисляет d3. Смещение тела
|
|
19380
|
+
// берём из offset-размеров, а не из getBoundingClientRect: они не искажаются масштабом превью и
|
|
19381
|
+
// transform предков, а координаты шкалы всегда в пикселях SVG.
|
|
19382
|
+
const customizeLine = useCallback(args => {
|
|
19383
|
+
customize?.(args);
|
|
19384
|
+
const body = lineBodyRef.current;
|
|
19385
|
+
const layout = body?.parentElement?.parentElement;
|
|
19386
|
+
if (!reportPlotInsets || !body || !layout)
|
|
19387
|
+
return;
|
|
19388
|
+
const bodyLeft = body.offsetLeft - layout.offsetLeft;
|
|
19389
|
+
const [plotLeft, plotRight] = args.xScale.range();
|
|
19390
|
+
reportPlotInsets({
|
|
19391
|
+
left: Math.round(bodyLeft + plotLeft),
|
|
19392
|
+
right: Math.round(layout.offsetWidth - bodyLeft - plotRight),
|
|
19393
|
+
width: layout.offsetWidth,
|
|
19394
|
+
});
|
|
19395
|
+
}, [customize, reportPlotInsets, lineBodyRef]);
|
|
18921
19396
|
const { formatFilterColor, onFilter } = useWidgetFilters(type, filterName, data?.[0]?.items);
|
|
18922
19397
|
const formattedAttributes = useMemo(() => getFormattedAttributes(t, (data[0]?.items || []), attributes, element), [attributes, data, element, t]);
|
|
18923
19398
|
const totalSum = useMemo(() => isRelated
|
|
@@ -18976,6 +19451,17 @@ const Chart = memo(({ config, element, elementConfig, type, renderElement }) =>
|
|
|
18976
19451
|
left: markersMargin,
|
|
18977
19452
|
};
|
|
18978
19453
|
}, [showMarkers, markers?.length]);
|
|
19454
|
+
// Значения шкалы барчарта d3 центрирует на делении, и крайние деления наполовину выступают за поле.
|
|
19455
|
+
// При нулевом поле SVG выступ уходит за SVG, где его срезает BarChartContainer (overflow-x: hidden,
|
|
19456
|
+
// отчего и по вертикали содержимое не visible). Место под выступ резервируем внутри SVG — внешние
|
|
19457
|
+
// размеры обёрток не меняются. Без значений шкалы (showLabels) выступать нечему.
|
|
19458
|
+
const barMargin = useMemo(() => showLabels
|
|
19459
|
+
? {
|
|
19460
|
+
...margin,
|
|
19461
|
+
top: Math.max(margin.top, Y_AXIS_LABEL_OVERHANG),
|
|
19462
|
+
bottom: Math.max(margin.bottom, Y_AXIS_LABEL_OVERHANG),
|
|
19463
|
+
}
|
|
19464
|
+
: margin, [showLabels, margin]);
|
|
18979
19465
|
const formatTooltipName = useCallback((name) => isRelated ? name : tooltipNameFromAttributes(name, formattedAttributes), [formattedAttributes, isRelated]);
|
|
18980
19466
|
const formatTooltipValue = useCallback((value, name) => isRelated
|
|
18981
19467
|
? tooltipValueFromRelatedFeatures(t, value, relatedAttributes, data[0]?.layerInfo)
|
|
@@ -19002,26 +19488,42 @@ const Chart = memo(({ config, element, elementConfig, type, renderElement }) =>
|
|
|
19002
19488
|
attributeUnits: item.attributeUnits,
|
|
19003
19489
|
dataSourceName: item.dataSourceName,
|
|
19004
19490
|
stroke: item.color || primaryColor,
|
|
19491
|
+
axis: item.axisSide ?? "left",
|
|
19005
19492
|
values: item.items
|
|
19006
19493
|
?.filter(({ value }) => !isEmptyValue(value))
|
|
19007
19494
|
?.map(({ value }) => Number(value)),
|
|
19008
19495
|
}));
|
|
19009
|
-
const isHidedY =
|
|
19010
|
-
const
|
|
19011
|
-
.
|
|
19496
|
+
const isHidedY = hideLeftAxis && hideRightAxis;
|
|
19497
|
+
const valuesOfSide = (side) => lineChartData
|
|
19498
|
+
.filter(({ axis }) => axis === side)
|
|
19012
19499
|
.map(({ values }) => values)
|
|
19013
19500
|
.flat();
|
|
19501
|
+
const leftValues = valuesOfSide("left");
|
|
19502
|
+
const rightValues = valuesOfSide("right");
|
|
19014
19503
|
// Резервируем нижнюю полосу под подписи оси X: без неё ось прижата к нижней границе,
|
|
19015
19504
|
// подписи (сдвинутые на +16px) вылезают за тело и режутся overflow: hidden у ChartFillMeasure.
|
|
19505
|
+
// Сверху резервируем выступ верхнего деления шкалы: оно центрировано на линии сетки и при нулевом
|
|
19506
|
+
// поле наполовину уходит за SVG, где в fill его срезает overflow: hidden у ChartFillMeasure.
|
|
19507
|
+
const topOverhang = Math.max(Y_AXIS_LABEL_OVERHANG - margin.top, 0);
|
|
19016
19508
|
const lineMargin = {
|
|
19017
19509
|
...margin,
|
|
19510
|
+
top: margin.top + topOverhang,
|
|
19018
19511
|
bottom: Math.max(margin.bottom, LINE_CHART_LABEL_MARGIN),
|
|
19019
19512
|
};
|
|
19020
|
-
|
|
19021
|
-
|
|
19022
|
-
|
|
19023
|
-
|
|
19024
|
-
|
|
19513
|
+
// draw.ts вычитает верхнее поле и из нижней границы поля графика — компенсируем добавленное,
|
|
19514
|
+
// чтобы низ поля и зазор до подписей оси X остались на месте.
|
|
19515
|
+
const lineXAxisPadding = LINE_CHART_X_AXIS_PADDING - topOverhang;
|
|
19516
|
+
// Колонки вертикальных подписей повторяют поля SVG, чтобы подпись центрировалась по полю
|
|
19517
|
+
// графика, а не по всей высоте вместе с подписями оси X.
|
|
19518
|
+
const plotTop = lineMargin.top;
|
|
19519
|
+
const plotBottom = lineMargin.top + lineMargin.bottom + lineXAxisPadding;
|
|
19520
|
+
return (jsxs(AnyChartWrapper, { height: lineWrapperHeight, children: [jsx(LineChartStyles, {}), jsxs(LineChartLayout, { children: [hasTopTitles && (jsx(AxisTitlesTop, { left: axisTitles.left, right: axisTitles.right, neutralColor: axisTitleColor })), jsxs(LineChartRow, { children: [hasSideTitles && (jsx(AxisTitleSideSlot, { side: "left", axisTitle: axisTitles.left, neutralColor: axisTitleColor, plotTop: plotTop, plotBottom: plotBottom })), jsx(LineChartBody, { ref: lineBodyRef, children: jsx(LineChart, { data: lineChartData, labels: labels, markers: markers, width: lineBodyWidth, height: lineBodyHeight, xAxisPadding: lineXAxisPadding, yAxisPadding: 0, min: leftValues.length ? Math.min(...leftValues) : undefined, rightMin: rightValues.length ? Math.min(...rightValues) : undefined, customYAxisSelection: yAxis => {
|
|
19521
|
+
// Обе оси приходят в один колбэк, поэтому сторону определяем по классу.
|
|
19522
|
+
const isRight = yAxis.classed(lineChartClassNames.lineChartYScaleRight);
|
|
19523
|
+
if (isRight ? hideRightAxis : hideLeftAxis) {
|
|
19524
|
+
yAxis.remove();
|
|
19525
|
+
}
|
|
19526
|
+
}, customYAxis: yAxis => yAxis.ticks(LINE_CHART_Y_TICKS).tickFormat(formatLeftTick), customYAxisRight: yAxis => yAxis.ticks(LINE_CHART_Y_TICKS).tickFormat(formatRightTick), renderTooltip: renderLineChartTooltip, customize: customizeLine, dotSnapping: dotSnapping, dynamicTooltipEnable: true, stackedTooltip: true, tooltipClassName: "dashboardLineChartTooltip", drawGridX: !isHidedY, margin: lineMargin }) }), hasSideTitles && (jsx(AxisTitleSideSlot, { side: "right", axisTitle: axisTitles.right, neutralColor: axisTitleColor, plotTop: plotTop, plotBottom: plotBottom }))] })] })] }));
|
|
19025
19527
|
}
|
|
19026
19528
|
if (isStackBar) {
|
|
19027
19529
|
// Вне fill chartHeight — высота самой полосы, и обёртка честно становится выше на строку
|
|
@@ -19051,7 +19553,7 @@ const Chart = memo(({ config, element, elementConfig, type, renderElement }) =>
|
|
|
19051
19553
|
const barRadius = options?.cornerRadius ?? DEFAULT_BARCHART_RADIUS;
|
|
19052
19554
|
bars.attr("rx", barRadius);
|
|
19053
19555
|
bars.attr("ry", barRadius);
|
|
19054
|
-
}, margin:
|
|
19556
|
+
}, margin: barMargin, xAxisPadding: 0, yAxisPadding: 0, formatTooltipValue: formatTooltipValue, formatTooltipName: formatTooltipName, hideTooltipGroupName: true, dynamicTooltipEnable: true, isBarTooltip: true, onBarClick: filterName ? item => onFilter(item.name) : undefined }) }) }));
|
|
19055
19557
|
}, [
|
|
19056
19558
|
customXAxisBottom,
|
|
19057
19559
|
customYAxisLeft,
|
|
@@ -19067,6 +19569,15 @@ const Chart = memo(({ config, element, elementConfig, type, renderElement }) =>
|
|
|
19067
19569
|
formatFilterColor,
|
|
19068
19570
|
chartWidth,
|
|
19069
19571
|
chartHeight,
|
|
19572
|
+
lineBodyWidth,
|
|
19573
|
+
lineBodyHeight,
|
|
19574
|
+
lineWrapperHeight,
|
|
19575
|
+
axisTitles,
|
|
19576
|
+
hasTopTitles,
|
|
19577
|
+
hasSideTitles,
|
|
19578
|
+
axisTitleColor,
|
|
19579
|
+
hideLeftAxis,
|
|
19580
|
+
hideRightAxis,
|
|
19070
19581
|
fitsHeight,
|
|
19071
19582
|
pieSide,
|
|
19072
19583
|
fill,
|
|
@@ -19076,11 +19587,14 @@ const Chart = memo(({ config, element, elementConfig, type, renderElement }) =>
|
|
|
19076
19587
|
formatTooltipValue,
|
|
19077
19588
|
formatTooltipName,
|
|
19078
19589
|
filterName,
|
|
19079
|
-
axes,
|
|
19080
19590
|
labels,
|
|
19081
19591
|
margin,
|
|
19592
|
+
barMargin,
|
|
19082
19593
|
renderLineChartTooltip,
|
|
19083
|
-
|
|
19594
|
+
customizeLine,
|
|
19595
|
+
lineBodyRef,
|
|
19596
|
+
formatLeftTick,
|
|
19597
|
+
formatRightTick,
|
|
19084
19598
|
primaryColor,
|
|
19085
19599
|
type,
|
|
19086
19600
|
elementConfig?.children,
|
|
@@ -19097,14 +19611,14 @@ const Chart = memo(({ config, element, elementConfig, type, renderElement }) =>
|
|
|
19097
19611
|
]);
|
|
19098
19612
|
if (!isVisibleContainer(id, expandable, expanded, expandedContainers))
|
|
19099
19613
|
return null;
|
|
19100
|
-
const chartBody = (jsxs(ChartWrapper, { width: isPieChart && fill ? pieSide : width, height: isStackBar ? "auto" : isPieChart ? (fill ? pieSide : width) : chartHeight, column: column, loading: loading, children: [jsx(ChartTooltipStyles, {}), renderChart] }));
|
|
19614
|
+
const chartBody = (jsxs(ChartWrapper, { width: isPieChart && fill ? pieSide : width, height: isStackBar ? "auto" : isPieChart ? (fill ? pieSide : width) : isLineChart ? lineWrapperHeight : chartHeight, column: column, loading: loading, children: [jsx(ChartTooltipStyles, {}), renderChart] }));
|
|
19101
19615
|
if (!fill)
|
|
19102
19616
|
return chartBody;
|
|
19103
19617
|
// fill: тело центрируется в измеряемой обёртке, ref которой питает ResizeObserver обеими осями.
|
|
19104
19618
|
return jsx(ChartFillMeasure, { ref: chartRef, children: chartBody });
|
|
19105
19619
|
});
|
|
19106
19620
|
|
|
19107
|
-
const ChartLegend = ({ data, chartElement, fontSize, type, twoColumns, loading }) => {
|
|
19621
|
+
const ChartLegend = ({ data, chartElement, fontSize, type, twoColumns, column, loading }) => {
|
|
19108
19622
|
const { t } = useGlobalContext();
|
|
19109
19623
|
const { sliceItems, showMore, onShowMore } = useShownOtherItems(chartElement?.options);
|
|
19110
19624
|
const axes = useMemo(() => getChartAxes(chartElement), [chartElement]);
|
|
@@ -19113,7 +19627,7 @@ const ChartLegend = ({ data, chartElement, fontSize, type, twoColumns, loading }
|
|
|
19113
19627
|
const showMoreBtn = !!shownItems && data.length > shownItems;
|
|
19114
19628
|
if (!loading && !data?.length && !!hideEmpty)
|
|
19115
19629
|
return null;
|
|
19116
|
-
return (jsxs(Flex, { flexDirection: "column", opacity: loading ? FILTERED_VALUE_OPACITY / 100 : 1, children: [jsx(ChartLegendContainer, { twoColumns: twoColumns, children: sliceItems(data)?.map(({ name, color }, index) => (jsxs(ChartLegendItem, { hasAnyFilter: hasAnyFilter, isFiltered: isFiltered(name), onClick: axes?.[0]?.filterName ? () => onFilter(name) : undefined, children: [jsx(ChartLegendColor, { color: color }), jsx(ChartLegendName, { "$fontSize": fontSize, "$fontColor": fontColor, children: name })] }, index))) }), showMoreBtn && (jsx(LegendToggler, { onClick: onShowMore, toggled: showMore, children: t("other", { ns: "dashboard", defaultValue: "Другое" }) }))] }));
|
|
19630
|
+
return (jsxs(Flex, { flexDirection: "column", opacity: loading ? FILTERED_VALUE_OPACITY / 100 : 1, children: [jsx(ChartLegendContainer, { twoColumns: twoColumns, "$column": column, children: sliceItems(data)?.map(({ name, color }, index) => (jsxs(ChartLegendItem, { hasAnyFilter: hasAnyFilter, isFiltered: isFiltered(name), onClick: axes?.[0]?.filterName ? () => onFilter(name) : undefined, children: [jsx(ChartLegendColor, { color: color }), jsx(ChartLegendName, { "$fontSize": fontSize, "$fontColor": fontColor, children: name })] }, index))) }), showMoreBtn && (jsx(LegendToggler, { onClick: onShowMore, toggled: showMore, children: t("other", { ns: "dashboard", defaultValue: "Другое" }) }))] }));
|
|
19117
19631
|
};
|
|
19118
19632
|
|
|
19119
19633
|
const ContainerChildren = memo(({ type, items, isColumn, isMain, renderElement }) => {
|
|
@@ -19968,5 +20482,5 @@ const DEFAULT_HEATMAP_STYLE = {
|
|
|
19968
20482
|
],
|
|
19969
20483
|
};
|
|
19970
20484
|
|
|
19971
|
-
export { ALIGNMENTS, ALIGN_ITEMS, ATTRIBUTE_ICON_ELEMENT_TYPES, AddButtonRow, AddFeatureButton, AddFeatureContainer, AlertIconContainer, AttachmentContainer, AttributeGalleryContainer, AttributeLabel, BASE_CONTAINER_STYLE, BG_IMAGE_SLOT_ID, BaseMapTheme, CHART_TYPES, COMPACT_FRACTION_DIGITS, CONFIG_PAGES_ID, CONFIG_PAGE_ID, CONTAINERS_GROUP_DEFAULTS, CONTAINER_BODY_ATTRIBUTE, CONTAINER_BODY_FILL_STYLE, CameraContainer, Chart, ChartContainer, ChartLegend, ChartLoading, Container, ContainerBackground, ContainerChildren, ContainerLoading, ContainerRoot, ContainerTemplate, ContainerWrapper, ContainersGroupContainer, DASHBOARD_OVERLAY_Z_INDEX, DEFAULT_ATTRIBUTE_NAME, DEFAULT_BARCHART_RADIUS, DEFAULT_BASE_MAP, DEFAULT_BLUR, DEFAULT_CHART_ANGLE, DEFAULT_CHART_HEIGHT, DEFAULT_CHART_WIDTH, DEFAULT_CIRCLE_RADIUS, DEFAULT_CIRCLE_STROKE_WIDTH, DEFAULT_CIRCLE_STYLE, DEFAULT_COLOR, DEFAULT_DASHBOARD_CONFIG, DEFAULT_DATA_SOURCE_LIMIT, DEFAULT_DROPDOWN_WIDTH, DEFAULT_FILL_EXTRUSION_BASE, DEFAULT_FILL_EXTRUSION_HEIGHT, DEFAULT_FILL_EXTRUSION_STYLE, DEFAULT_FILL_EXTRUSION_VERTICAL_GRADIENT, DEFAULT_FILL_STYLE, DEFAULT_FILTER_PADDING, DEFAULT_GRID_GAP, DEFAULT_HEATMAP_COLOR, DEFAULT_HEATMAP_INTENSITY, DEFAULT_HEATMAP_RADIUS, DEFAULT_HEATMAP_STYLE, DEFAULT_HEATMAP_WEIGHT, DEFAULT_ICON_ANCHOR, DEFAULT_ICON_OVERLAP, DEFAULT_ICON_PADDING, DEFAULT_ICON_ROTATE, DEFAULT_ICON_SIZE, DEFAULT_ID_ATTRIBUTE_NAME, DEFAULT_LAT, DEFAULT_LINE_CAP, DEFAULT_LINE_JOIN, DEFAULT_LINE_STYLE, DEFAULT_LINE_WIDTH, DEFAULT_LNG, DEFAULT_OPACITY, DEFAULT_PAGES_CONFIG, DEFAULT_PIECHART_RADIUS, DEFAULT_SYMBOL_COLOR, DEFAULT_SYMBOL_HALO_COLOR, DEFAULT_SYMBOL_PLACEMENT, DEFAULT_SYMBOL_SPACING, DEFAULT_SYMBOL_STYLE, DEFAULT_TEXT_ANCHOR, DEFAULT_TEXT_JUSTIFY, DEFAULT_TEXT_SIZE, DEFAULT_TEXT_TRANSFORM, DEFAULT_TRACK_FR, DEFAULT_TRANSLATE, DEFAULT_ZOOM, DRAG_THRESHOLD_PX, Dashboard, DashboardCheckbox, DashboardChip, DashboardContent, DashboardContext, DashboardDefaultHeader, DashboardHeader, DashboardLoading, DashboardPlaceholder, DashboardPlaceholderWrap, DashboardProvider, DashboardWrapper, DataSourceContainer, DataSourceError, DataSourceErrorContainer, DataSourceInnerContainer, DataSourceProgressContainer, DateFormat, DefaultAttributesContainer, DefaultHeaderContainer, DefaultHeaderWrapper, DividerContainer, EMPTY_DATA_SOURCE_LAYER_INFO, EXTENT_FILTER_NAME, EditGeometryType, ElementButton, ElementCamera, ElementChart, ElementChips, ElementControl, ElementIcon, ElementImage, ElementLegend, ElementLink, ElementMarkdown, ElementSlideshow, ElementSvg, ElementTable, ElementTooltip, ElementValueWrapper, ExpandableTitle, FEATURE_CARD_DEFAULT_COLORS, FEATURE_CARD_OTHER_COLOR, FILL_SIZE, FILTERED_VALUE_OPACITY, FILTER_PREFIX, FR_PRECISION, FeatureCardBackgroundHeader, FeatureCardButtons, FeatureCardContext, FeatureCardDefaultHeader, FeatureCardHeader, FeatureCardProvider, FeatureCardSlideshowHeader, FeatureCardTitle, FeatureControls, FeatureTitleContainer, FiltersContainer, GEOMETRY_ATTRIBUTE, GEOMETRY_FILTER_NAME, GRID_AUTO_FILL_DEFAULTS, GRID_CELL_ATTR, GRID_CELL_ID_PREFIX, GRID_DRAGGING_ATTR, GRID_DRAG_SOURCE_ATTR, GRID_DROP_TARGET_ATTR, GRID_FILL_DEFAULTS, GRID_ROW_ID_PREFIX, GlobalContext, GlobalProvider, GridRowContainer, HANDLE_BLEED_PX, Header, HeaderContainer, HeaderFontColorMixin, HeaderFrontView, HeaderTemplate, HeaderTitleContainer, HiddenTitleItems, IconContainer, ImageContainer, LEFT_PANEL_HEADER_HEIGHT, Layer, LayerDescription, LayerGroupList, LayerIcon, LayerIconContainer, LayerListContainer, LayerTree, LayersContainer, LayersListWrapper, LinearProgressContainer, LogTerminal, LogoContainer, MAP_VIEW_FILTER_NAMES, MAX_CHART_WIDTH, MAX_TRACKS, MIN_TRACK_PX, MIN_TRACK_RATIO, Map$1 as Map, MapContext, MapProvider, NON_TRACK_SLOT_IDS, NO_CELL_DRAG_SELECTOR, NO_CONTENT_VALUE, NUMERIC_ATTRIBUTE_TYPES, NoLiveSnapshotContainer, OBJECT_FITS, OVERFLOWS, OneColumnContainer, PIE_CHART_TOOLTIP_STYLE, POLL_SUBTASK_INTERVAL_MS, POLL_SUBTASK_TIMEOUT_MS, PROJECT_ALIAS_PROP, PROJECT_FILTER_NAME, PROJECT_NAME_PROP, PROJECT_PROPS, PROVIDER_PREFIX, PageNavigator, PageTitle, PageTitleContainer, PagesContainer, Pagination, PresentationHeader, PresentationHeaderButtons, PresentationHeaderTools, PresentationPanelContainer, PresentationPanelWrapper, PresentationWrapper, ProgressContainer, ProviderPrefix, QUERY_DESCRIPTION_CACHE_TTL, RESIZE_HANDLE_ATTR, ResizeHandle, RoundedBackgroundContainer, SAVE_HOOK_RESULT_DURATION, SERVER_NOTIFICATION_EVENT, STACK_BAR_TOTAL_HEIGHT, ScalingFactor, ServerNotificationsContext, ServerNotificationsProvider, SlideshowContainer, SmallPreviewContainer$1 as SmallPreviewContainer, SmallPreviewControl, SmallPreviewCounter, SmallPreviewImages, SmallPreviewLeft, SmallPreviewRight, StackBar, StructuredDataContainer, SvgImage, TILE_ALIGNMENTS, TIME_ZONE_FORMAT, TITLE_SLOT_IDS, TabsContainer, TextTrim, ThemeName, TitleContainer, TopContainer, TopContainerButtons, TwoColumnContainer, UploadContainer, VIEW_MODES, VoteContainer, WidgetType, ZOOM_FILTER_NAME, addDataSource, addDataSources, adjustColor, applyFiltersToCondition, applyQueryFilters, applyTreeFilterToCondition, applyVarsToCondition, asAttributeName, asChartId, asContainerId, asDataSourceName, asFilterName, asLayerName, asModalId, asResourceId, asTabId, buildGridTemplate, buildTrackTemplate, checkEqualOrIncludes, checkIsLoading, collectConfigIds, colorToHex, containsNodeId, createConfigLayer, createConfigPage, createGridCell, createGridIdFactory, createGridRow, createNewPageId, createSaveNotificationId, dateOptions, debounce, decimalOpacityToHex, enrichStyleItemsWithIds, enrichStyleModelsWithIds, eqlParametersToPayload, fetchQueryDescription, findAttributeInExpression, findCellContext, formatArea, formatAttributeValue, formatChartRelatedValue, formatConditionValue, formatDataSourceCondition, formatDate$1 as formatDate, formatElementValue, formatLength, formatNumber, formatPolygonMeasure, geometryToEwkt, getActualExtrusionHeight, getAttributeByName, getAttributeConfigurationByName, getAttributeIconElement, getAttributeIconUrl, getAttributeValue, getAttributesConfiguration, getAverageTrackSize, getChartAxes, getChartFilterName, getChartMarkers, getConfigFilter, getContainerComponent, getDashboardHeader, getDataFromAttributes, getDataFromRelatedFeatures, getDataSource, getDataSourceFilterValue, getDataSourceLayerInfo, getDate, getDefaultConfig, getDisplayTemplateNameFromAttribute, getElementValue, getFeatureAttributes, getFeatureCardHeader, getFilterComponent, getFilterSelectedItems, getFilterValue, getFormattedAttributes, getGradientColors, getImageUrl, getLayerClientStyle, getLayerInfo, getLayerInfoAttribute, getLayerInfoFromDataSources, getLayoutChildren, getMapViewDataSources, getModalsDataSources, getPagesFromConfig, getPagesFromProjectInfo, getProjectValue, getProxyService, getRelatedAttribute, getRenderElement, getResourceUrl, getRootElementId, getSelectedFilterValue, getShownItemsLimit, getSlideshowImages, getStyleAttributes, getSvgUrl, getTemplateNameFromAttribute, getThemeByName, getTotalFromAttributes, getTotalFromRelatedFeatures, getTrackSize, getTrackSizeKey, getTrackSizes, getWrapperSizeStyle, hasContainerBgImage, hexToRgba, isCrossOriginUrl, isEmptyElementValue, isEmptyValue, isFeaturesFilterValue, isFillSize, isFrSize, isGridNode, isHiddenEmptyValue, isHookActive, isLayerService, isNotValidSelectedTab, isNumeric, isObject, isProxyService, isRootOwningContainer, isTreeFilterValue, isVisibleContainer, mapNodeById, mergeAttributeConfigurations, metersPerPixel, noMarginMixin, numberOptions, parseFrValue, parseIconNames, parseIconNamesFromClientStyle, pieChartTooltipFromAttributes, pieChartTooltipFromRelatedFeatures, pointOptions, removeDataSource, removeTracks, replaceNodesByIds, rgbToHex, roundFr, roundTotalSum, setLayoutChildren, sizeCssMixin, sliceShownOtherItems, stretchPalette, timeOptions, toConditionsArray, toCssSize, toFrSize, toPxNumber, toRenderableValue, tooltipNameFromAttributes, tooltipValueFromAttributes, tooltipValueFromRelatedFeatures, transparentizeColor, updateDataSource, useAfterSave, useAppHeight, useAttachmentDownload, useAttachmentItems, useAttachmentPreviewImages, useAttachmentsView, useAutoCompleteControl, useBeforeSave, useBgImageHost, useChartChange, useChartData, useConfigDataSources, useContainerAttributes, useContainerRoot, useCurrentPageLayers, useCustomFeatureSelect, useDashboardHeader, useDataSourceLoading, useDataSources, useDebouncedCallback, useDiffPage, useEditGroupAttributes, useEqualTileWidth, useExpandableContainers, useExportPdf, useFeatureSaveHooks, useFetchImageWithAuth, useFetchWithAuth, useGetConfigLayer, useGlobalContext, useHeaderRender, useHideIfEmptyDataSource, useLayerHiddenAttributes, useLayerParams, useMapContext, useMapDraw, useMapImages, useMaxZoomTo, useProjectDashboardInit, usePythonSandbox, usePythonTask, useRedrawLayer, useRelatedDataSourceAttributes, useRemoteTask, useRenderElement, useResizeBox, useResizeDrag, useSavePrototypeBuilder, useServerNotificationsContext, useShownOtherItems, useToggle, useUpdateDataSource, useVisibleProjectItems, useWidgetConfig, useWidgetContext, useWidgetFilters, useWidgetPage, useWindowResize, useWrapperSize, useZoomToFeatures, useZoomToPoint, withTrackSize };
|
|
20485
|
+
export { ALIGNMENTS, ALIGN_ITEMS, ATTRIBUTE_ICON_ELEMENT_TYPES, AXIS_TITLE_GAP, AXIS_TITLE_LINE_HEIGHT, AXIS_TITLE_TOP_GRID_GAP, AXIS_TITLE_TOP_HEIGHT, AddButtonRow, AddFeatureButton, AddFeatureContainer, AlertIconContainer, AttachmentContainer, AttributeGalleryContainer, AttributeLabel, BASE_CONTAINER_STYLE, BG_IMAGE_SLOT_ID, BaseMapTheme, CHART_AXIS_ALIGN_JUSTIFY, CHART_TYPES, COMPACT_FRACTION_DIGITS, CONFIG_PAGES_ID, CONFIG_PAGE_ID, CONTAINERS_GROUP_DEFAULTS, CONTAINER_BODY_ATTRIBUTE, CONTAINER_BODY_FILL_STYLE, CameraContainer, Chart, ChartContainer, ChartLegend, ChartLoading, Container, ContainerBackground, ContainerChildren, ContainerLoading, ContainerRoot, ContainerTemplate, ContainerWrapper, ContainersGroupContainer, DASHBOARD_OVERLAY_Z_INDEX, DEFAULT_ATTRIBUTE_NAME, DEFAULT_BARCHART_RADIUS, DEFAULT_BASE_MAP, DEFAULT_BLUR, DEFAULT_CHART_ANGLE, DEFAULT_CHART_HEIGHT, DEFAULT_CHART_WIDTH, DEFAULT_CIRCLE_RADIUS, DEFAULT_CIRCLE_STROKE_WIDTH, DEFAULT_CIRCLE_STYLE, DEFAULT_COLOR, DEFAULT_DASHBOARD_CONFIG, DEFAULT_DATA_SOURCE_LIMIT, DEFAULT_DROPDOWN_WIDTH, DEFAULT_FILL_EXTRUSION_BASE, DEFAULT_FILL_EXTRUSION_HEIGHT, DEFAULT_FILL_EXTRUSION_STYLE, DEFAULT_FILL_EXTRUSION_VERTICAL_GRADIENT, DEFAULT_FILL_STYLE, DEFAULT_FILTER_PADDING, DEFAULT_GRID_GAP, DEFAULT_HEATMAP_COLOR, DEFAULT_HEATMAP_INTENSITY, DEFAULT_HEATMAP_RADIUS, DEFAULT_HEATMAP_STYLE, DEFAULT_HEATMAP_WEIGHT, DEFAULT_ICON_ANCHOR, DEFAULT_ICON_OVERLAP, DEFAULT_ICON_PADDING, DEFAULT_ICON_ROTATE, DEFAULT_ICON_SIZE, DEFAULT_ID_ATTRIBUTE_NAME, DEFAULT_LAT, DEFAULT_LINE_CAP, DEFAULT_LINE_JOIN, DEFAULT_LINE_STYLE, DEFAULT_LINE_WIDTH, DEFAULT_LNG, DEFAULT_OPACITY, DEFAULT_PAGES_CONFIG, DEFAULT_PIECHART_RADIUS, DEFAULT_SYMBOL_COLOR, DEFAULT_SYMBOL_HALO_COLOR, DEFAULT_SYMBOL_PLACEMENT, DEFAULT_SYMBOL_SPACING, DEFAULT_SYMBOL_STYLE, DEFAULT_TEXT_ANCHOR, DEFAULT_TEXT_JUSTIFY, DEFAULT_TEXT_SIZE, DEFAULT_TEXT_TRANSFORM, DEFAULT_TRACK_FR, DEFAULT_TRANSLATE, DEFAULT_ZOOM, DRAG_THRESHOLD_PX, Dashboard, DashboardCheckbox, DashboardChip, DashboardContent, DashboardContext, DashboardDefaultHeader, DashboardHeader, DashboardLoading, DashboardPlaceholder, DashboardPlaceholderWrap, DashboardProvider, DashboardWrapper, DataSourceContainer, DataSourceError, DataSourceErrorContainer, DataSourceInnerContainer, DataSourceProgressContainer, DateFormat, DefaultAttributesContainer, DefaultHeaderContainer, DefaultHeaderWrapper, DividerContainer, EMPTY_DATA_SOURCE_LAYER_INFO, EXTENT_FILTER_NAME, EditGeometryType, ElementButton, ElementCamera, ElementChart, ElementChips, ElementControl, ElementIcon, ElementImage, ElementLegend, ElementLink, ElementMarkdown, ElementSlideshow, ElementSvg, ElementTable, ElementTooltip, ElementValueWrapper, ExpandableTitle, FEATURE_CARD_DEFAULT_COLORS, FEATURE_CARD_OTHER_COLOR, FILL_SIZE, FILTERED_VALUE_OPACITY, FILTER_PREFIX, FR_PRECISION, FeatureCardBackgroundHeader, FeatureCardButtons, FeatureCardContext, FeatureCardDefaultHeader, FeatureCardHeader, FeatureCardProvider, FeatureCardSlideshowHeader, FeatureCardTitle, FeatureControls, FeatureTitleContainer, FiltersContainer, GEOMETRY_ATTRIBUTE, GEOMETRY_FILTER_NAME, GRID_AUTO_FILL_DEFAULTS, GRID_CELL_ATTR, GRID_CELL_ID_PREFIX, GRID_DRAGGING_ATTR, GRID_DRAG_SOURCE_ATTR, GRID_DROP_TARGET_ATTR, GRID_FILL_DEFAULTS, GRID_ROW_ID_PREFIX, GlobalContext, GlobalProvider, GridRowContainer, HANDLE_BLEED_PX, Header, HeaderContainer, HeaderFontColorMixin, HeaderFrontView, HeaderTemplate, HeaderTitleContainer, HiddenTitleItems, IconContainer, ImageContainer, LEFT_PANEL_HEADER_HEIGHT, LINE_CHART_X_LABELS_BLANK, LINE_CHART_Y_TICKS, Layer, LayerDescription, LayerGroupList, LayerIcon, LayerIconContainer, LayerListContainer, LayerTree, LayersContainer, LayersListWrapper, LinearProgressContainer, LogTerminal, LogoContainer, MAP_VIEW_FILTER_NAMES, MAX_CHART_WIDTH, MAX_TRACKS, MIN_TRACK_PX, MIN_TRACK_RATIO, Map$1 as Map, MapContext, MapProvider, NON_TRACK_SLOT_IDS, NO_CELL_DRAG_SELECTOR, NO_CONTENT_VALUE, NUMERIC_ATTRIBUTE_TYPES, NoLiveSnapshotContainer, OBJECT_FITS, OVERFLOWS, OneColumnContainer, PIE_CHART_TOOLTIP_STYLE, POLL_SUBTASK_INTERVAL_MS, POLL_SUBTASK_TIMEOUT_MS, PROJECT_ALIAS_PROP, PROJECT_FILTER_NAME, PROJECT_NAME_PROP, PROJECT_PROPS, PROVIDER_PREFIX, PageNavigator, PageTitle, PageTitleContainer, PagesContainer, Pagination, PresentationHeader, PresentationHeaderButtons, PresentationHeaderTools, PresentationPanelContainer, PresentationPanelWrapper, PresentationWrapper, ProgressContainer, ProviderPrefix, QUERY_DESCRIPTION_CACHE_TTL, RESIZE_HANDLE_ATTR, ResizeHandle, RoundedBackgroundContainer, SAVE_HOOK_RESULT_DURATION, SERVER_NOTIFICATION_EVENT, STACK_BAR_TOTAL_HEIGHT, ScalingFactor, ServerNotificationsContext, ServerNotificationsProvider, SlideshowContainer, SmallPreviewContainer$1 as SmallPreviewContainer, SmallPreviewControl, SmallPreviewCounter, SmallPreviewImages, SmallPreviewLeft, SmallPreviewRight, StackBar, StructuredDataContainer, SvgImage, TILE_ALIGNMENTS, TIME_ZONE_FORMAT, TITLE_SLOT_IDS, TabsContainer, TextTrim, ThemeName, TitleContainer, TopContainer, TopContainerButtons, TwoColumnContainer, UploadContainer, VIEW_MODES, VoteContainer, WidgetType, X_AXIS_TITLE_GAP, X_AXIS_TITLE_LEGEND_GAP, Y_AXIS_LABEL_OVERHANG, ZOOM_FILTER_NAME, addDataSource, addDataSources, adjustColor, applyFiltersToCondition, applyQueryFilters, applyTreeFilterToCondition, applyVarsToCondition, asAttributeName, asChartId, asContainerId, asDataSourceName, asFilterName, asLayerName, asModalId, asResourceId, asTabId, buildGridTemplate, buildTrackTemplate, checkEqualOrIncludes, checkIsLoading, collectConfigIds, colorToHex, containsNodeId, createConfigLayer, createConfigPage, createGridCell, createGridIdFactory, createGridRow, createNewPageId, createSaveNotificationId, dateOptions, debounce, decimalOpacityToHex, enrichStyleItemsWithIds, enrichStyleModelsWithIds, eqlParametersToPayload, fetchQueryDescription, findAttributeInExpression, findCellContext, formatArea, formatAttributeValue, formatChartRelatedValue, formatConditionValue, formatDataSourceCondition, formatDate$1 as formatDate, formatElementValue, formatLength, formatNumber, formatPolygonMeasure, geometryToEwkt, getActualExtrusionHeight, getAttributeByName, getAttributeConfigurationByName, getAttributeIconElement, getAttributeIconUrl, getAttributeValue, getAttributesConfiguration, getAverageTrackSize, getAxisSide, getChartAxes, getChartFilterName, getChartMarkers, getConfigFilter, getContainerComponent, getDashboardHeader, getDataFromAttributes, getDataFromRelatedFeatures, getDataSource, getDataSourceFilterValue, getDataSourceLayerInfo, getDate, getDefaultConfig, getDisplayTemplateNameFromAttribute, getElementValue, getFeatureAttributes, getFeatureCardHeader, getFilterComponent, getFilterSelectedItems, getFilterValue, getFormattedAttributes, getGradientColors, getImageUrl, getLayerClientStyle, getLayerInfo, getLayerInfoAttribute, getLayerInfoFromDataSources, getLayoutChildren, getMapViewDataSources, getModalsDataSources, getPagesFromConfig, getPagesFromProjectInfo, getProjectValue, getProxyService, getRelatedAttribute, getRenderElement, getResourceUrl, getRootElementId, getSelectedFilterValue, getShownItemsLimit, getSlideshowImages, getStyleAttributes, getSvgUrl, getTemplateNameFromAttribute, getThemeByName, getTotalFromAttributes, getTotalFromRelatedFeatures, getTrackSize, getTrackSizeKey, getTrackSizes, getWrapperSizeStyle, hasAxisConfig, hasContainerBgImage, hexToRgba, isCrossOriginUrl, isEmptyElementValue, isEmptyValue, isFeaturesFilterValue, isFillSize, isFrSize, isGridNode, isHiddenEmptyValue, isHookActive, isLayerService, isNotValidSelectedTab, isNumeric, isObject, isProxyService, isRightAxis, isRootOwningContainer, isTreeFilterValue, isValueAxis, isVisibleContainer, mapNodeById, mergeAttributeConfigurations, metersPerPixel, noMarginMixin, numberOptions, parseFrValue, parseIconNames, parseIconNamesFromClientStyle, pieChartTooltipFromAttributes, pieChartTooltipFromRelatedFeatures, pointOptions, removeDataSource, removeTracks, replaceNodesByIds, resolveAxis, rgbToHex, roundFr, roundTotalSum, setLayoutChildren, sizeCssMixin, sliceShownOtherItems, stretchPalette, timeOptions, toConditionsArray, toCssSize, toFrSize, toPxNumber, toRenderableValue, tooltipNameFromAttributes, tooltipValueFromAttributes, tooltipValueFromRelatedFeatures, transparentizeColor, updateDataSource, useAfterSave, useAppHeight, useAttachmentDownload, useAttachmentItems, useAttachmentPreviewImages, useAttachmentsView, useAutoCompleteControl, useBeforeSave, useBgImageHost, useChartAxisAttributes, useChartAxisTickFormat, useChartAxisTitles, useChartChange, useChartData, useConfigDataSources, useContainerAttributes, useContainerRoot, useCurrentPageLayers, useCustomFeatureSelect, useDashboardHeader, useDataSourceLoading, useDataSources, useDebouncedCallback, useDiffPage, useEditGroupAttributes, useEqualTileWidth, useExpandableContainers, useExportPdf, useFeatureSaveHooks, useFetchImageWithAuth, useFetchWithAuth, useGetConfigLayer, useGlobalContext, useHeaderRender, useHideIfEmptyDataSource, useLayerHiddenAttributes, useLayerParams, useMapContext, useMapDraw, useMapImages, useMaxZoomTo, useProjectDashboardInit, usePythonSandbox, usePythonTask, useRedrawLayer, useRelatedDataSourceAttributes, useRemoteTask, useRenderElement, useResizeBox, useResizeDrag, useSavePrototypeBuilder, useServerNotificationsContext, useShownOtherItems, useToggle, useUpdateDataSource, useVisibleProjectItems, useWidgetConfig, useWidgetContext, useWidgetFilters, useWidgetPage, useWindowResize, useWrapperSize, useZoomToFeatures, useZoomToPoint, withTrackSize };
|
|
19972
20486
|
//# sourceMappingURL=react.esm.js.map
|