@evergis/react 4.0.101 → 4.0.102
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 +1 -1
- package/dist/components/Dashboard/components/Chart/FillContext.d.ts +15 -0
- package/dist/components/Dashboard/components/Chart/styled.d.ts +1 -0
- package/dist/components/Dashboard/containers/EditContainer/styled.d.ts +2 -0
- package/dist/components/Dashboard/containers/styled.d.ts +4 -1
- package/dist/components/Dashboard/hooks/index.d.ts +1 -1
- package/dist/components/Dashboard/hooks/useResizeBox.d.ts +17 -0
- package/dist/components/Dashboard/types.d.ts +6 -2
- package/dist/index.js +110 -28
- package/dist/index.js.map +1 -1
- package/dist/react.esm.js +110 -28
- package/dist/react.esm.js.map +1 -1
- package/package.json +3 -3
- package/dist/components/Dashboard/components/Chart/ChartFillContext.d.ts +0 -8
- package/dist/components/Dashboard/hooks/useResizeWidth.d.ts +0 -12
|
@@ -154,7 +154,7 @@ export interface CameraContainerConfig extends Omit<ConfigContainerChild, "optio
|
|
|
154
154
|
export interface CameraContainerProps extends Omit<ContainerProps, "elementConfig"> {
|
|
155
155
|
elementConfig?: CameraContainerConfig;
|
|
156
156
|
}
|
|
157
|
-
export type ChartContainerOptions = Pick<ConfigOptions, "twoColumns" | "hideEmpty" | "width" | "height" | "
|
|
157
|
+
export type ChartContainerOptions = Pick<ConfigOptions, "twoColumns" | "hideEmpty" | "width" | "height" | "fill">;
|
|
158
158
|
export interface ChartAliasChild extends Omit<ConfigContainerChild, "id"> {
|
|
159
159
|
id: "alias";
|
|
160
160
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Значение контекста вписывания тела графика в контейнер (`options.fill` контейнера Chart). */
|
|
2
|
+
export interface FillContextValue {
|
|
3
|
+
/** Вписать тело графика в контейнер: по ширине всегда, по высоте — при заданной высоте (object-fit: contain). */
|
|
4
|
+
fill: boolean;
|
|
5
|
+
/** У контейнера ограниченная высота ⇒ можно фитить по высоте (иначе только по ширине). */
|
|
6
|
+
fitHeight: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Контекст вписывания графика (`options.fill` контейнера Chart).
|
|
10
|
+
*
|
|
11
|
+
* Компонент `Chart` рендерится через `renderElement({ id: "chart" })` и получает только дочерний
|
|
12
|
+
* узел `{ id: "chart" }` — опции контейнера до него не доходят. `ChartContainer` оборачивает
|
|
13
|
+
* график в провайдер этого контекста, а `Chart` читает значение через `useContext`.
|
|
14
|
+
*/
|
|
15
|
+
export declare const FillContext: import('react').Context<FillContextValue>;
|
|
@@ -15,6 +15,7 @@ export declare const PieChartCenter: import('styled-components').StyledComponent
|
|
|
15
15
|
export declare const ChartWrapperContainer: import('styled-components').StyledComponent<"div", any, {
|
|
16
16
|
column: boolean;
|
|
17
17
|
}, never>;
|
|
18
|
+
export declare const ChartFillMeasure: import('styled-components').StyledComponent<"div", any, {}, never>;
|
|
18
19
|
export declare const Tooltip: import('styled-components').StyledComponent<"div", any, {
|
|
19
20
|
transform?: CSSProperties["transform"];
|
|
20
21
|
}, never>;
|
|
@@ -2,9 +2,11 @@ export declare const CheckboxWrapper: import('styled-components').StyledComponen
|
|
|
2
2
|
fontColor?: string;
|
|
3
3
|
big?: boolean;
|
|
4
4
|
column?: boolean;
|
|
5
|
+
$fill?: boolean;
|
|
5
6
|
}, never>;
|
|
6
7
|
export declare const ChipsWrapper: import('styled-components').StyledComponent<"div", any, import('@evergis/uilib-gl').FlexProps & {
|
|
7
8
|
fontColor?: string;
|
|
8
9
|
big?: boolean;
|
|
9
10
|
column?: boolean;
|
|
11
|
+
$fill?: boolean;
|
|
10
12
|
}, never>;
|
|
@@ -2,13 +2,16 @@ export declare const ContainerAlias: import('styled-components').StyledComponent
|
|
|
2
2
|
hasBottomMargin?: boolean;
|
|
3
3
|
}, never>;
|
|
4
4
|
export declare const ContainerAliasIcon: import('styled-components').StyledComponent<"div", any, {}, never>;
|
|
5
|
-
export declare const ContainerChart: import('styled-components').StyledComponent<"div", any, import('@evergis/uilib-gl').FlexProps
|
|
5
|
+
export declare const ContainerChart: import('styled-components').StyledComponent<"div", any, import('@evergis/uilib-gl').FlexProps & {
|
|
6
|
+
$fill?: boolean;
|
|
7
|
+
}, never>;
|
|
6
8
|
export declare const ContainerLegend: import('styled-components').StyledComponent<"div", any, import('@evergis/uilib-gl').FlexProps, never>;
|
|
7
9
|
export declare const ContainerUnits: import('styled-components').StyledComponent<"div", any, {}, never>;
|
|
8
10
|
export declare const ContainerValue: import('styled-components').StyledComponent<"div", any, import('@evergis/uilib-gl').FlexProps & {
|
|
9
11
|
fontColor?: string;
|
|
10
12
|
big?: boolean;
|
|
11
13
|
column?: boolean;
|
|
14
|
+
$fill?: boolean;
|
|
12
15
|
}, never>;
|
|
13
16
|
export declare const ContainerIcon: import('styled-components').StyledComponent<"span", any, import('@evergis/uilib-gl').IIconProps & {
|
|
14
17
|
$fontColor?: string;
|
|
@@ -25,7 +25,7 @@ export * from './useHideIfEmptyDataSource';
|
|
|
25
25
|
export * from './useProjectDashboardInit';
|
|
26
26
|
export * from './useRelatedDataSourceAttributes';
|
|
27
27
|
export * from './useRenderElement';
|
|
28
|
-
export * from './
|
|
28
|
+
export * from './useResizeBox';
|
|
29
29
|
export * from './useShownOtherItems';
|
|
30
30
|
export * from './useUpdateDataSource';
|
|
31
31
|
export * from './useWidgetConfig';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
/** Измеренный content-box наблюдаемого элемента: обе оси в пикселях либо `undefined` до первого замера. */
|
|
3
|
+
export interface ResizeBox {
|
|
4
|
+
width?: number;
|
|
5
|
+
height?: number;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Измеряет фактические ширину и высоту DOM-элемента и обновляет их на любой ресайз (ResizeObserver).
|
|
9
|
+
*
|
|
10
|
+
* Возвращает `[ref, box]`, где `box` — `{ width, height }` в пикселях (content-box) либо пустой объект,
|
|
11
|
+
* пока элемент ещё не измерен. Используется для «резинового» графика: d3-графикам нужны конкретные
|
|
12
|
+
* пиксельные размеры, а не CSS `100%`, а для вписывания (fit) нужны обе оси.
|
|
13
|
+
*
|
|
14
|
+
* `enabled: false` полностью отключает наблюдение — обычные (не fill) графики не измеряются
|
|
15
|
+
* и не вызывают лишних ре-рендеров.
|
|
16
|
+
*/
|
|
17
|
+
export declare const useResizeBox: (enabled: boolean) => [RefObject<HTMLDivElement>, ResizeBox];
|
|
@@ -162,8 +162,8 @@ export interface ConfigLayoutOptions {
|
|
|
162
162
|
cornerRadius?: number;
|
|
163
163
|
column?: boolean;
|
|
164
164
|
twoColumns?: boolean;
|
|
165
|
-
/**
|
|
166
|
-
|
|
165
|
+
/** Вписать график контейнера Chart в контейнер: по ширине всегда, по высоте — при заданной высоте (object-fit: contain). */
|
|
166
|
+
fill?: boolean;
|
|
167
167
|
/** Горизонтальное выравнивание содержимого заголовка контейнера. */
|
|
168
168
|
align?: Alignment;
|
|
169
169
|
/** Выравнивание детей контейнера по поперечной оси. В ряду по умолчанию `center`. */
|
|
@@ -187,6 +187,10 @@ export interface MarkdownTagTypography {
|
|
|
187
187
|
fontSize?: FontSizeToken | string;
|
|
188
188
|
lineHeight?: string;
|
|
189
189
|
fontWeight?: number | string;
|
|
190
|
+
/** Отступ снизу — задаёт расстояние до следующего блока (между тегами). */
|
|
191
|
+
marginBottom?: string;
|
|
192
|
+
/** Отступ сверху — задаёт расстояние до предыдущего блока (между тегами). */
|
|
193
|
+
marginTop?: string;
|
|
190
194
|
}
|
|
191
195
|
/**
|
|
192
196
|
* Пер-тег типографика markdown-виджета. Отсутствующий тег или свойство —
|
package/dist/index.js
CHANGED
|
@@ -102,7 +102,30 @@ const ChartWrapperContainer = styled.div.withConfig({ displayName: "ChartWrapper
|
|
|
102
102
|
position: relative;
|
|
103
103
|
width: 100%;
|
|
104
104
|
`;
|
|
105
|
-
|
|
105
|
+
/*
|
|
106
|
+
* fill-режим: обёртка забирает всю доступную ячейку (её высоту задаёт флекс-цепочка, а не контент графика),
|
|
107
|
+
* на неё вешается ref для ResizeObserver — меряем обе оси без цикла. Плоский div (не Flex uilib), как соседний
|
|
108
|
+
* ChartWrapperContainer, чтобы ref гарантированно дошёл до DOM-узла. Тело графика центрируется внутри.
|
|
109
|
+
*/
|
|
110
|
+
const ChartFillMeasure = styled.div.withConfig({ displayName: "ChartFillMeasure", componentId: "sc-1r4oerb" }) `
|
|
111
|
+
position: relative;
|
|
112
|
+
display: flex;
|
|
113
|
+
align-items: center;
|
|
114
|
+
justify-content: center;
|
|
115
|
+
width: 100%;
|
|
116
|
+
height: 100%;
|
|
117
|
+
min-width: 0;
|
|
118
|
+
min-height: 0;
|
|
119
|
+
overflow: hidden;
|
|
120
|
+
|
|
121
|
+
/* SVG по умолчанию inline, поэтому под ним остаётся зазор базовой линии (~4px при line-height
|
|
122
|
+
18.4px): вне fill его скрывал запас высоты, а тело, точно заполнившее ячейку, из-за него
|
|
123
|
+
вылезает за нижнюю границу. Блочный SVG зазора не даёт. */
|
|
124
|
+
svg {
|
|
125
|
+
display: block;
|
|
126
|
+
}
|
|
127
|
+
`;
|
|
128
|
+
const Tooltip = styled.div.withConfig({ displayName: "Tooltip", componentId: "sc-1va8cy3" }) `
|
|
106
129
|
position: relative;
|
|
107
130
|
border-radius: 0.25rem;
|
|
108
131
|
background-color: rgba(28, 33, 48);
|
|
@@ -195,7 +218,7 @@ const LineChartStyles = styled.createGlobalStyle `
|
|
|
195
218
|
fill: ${({ theme: { palette } }) => palette.textDisabled};
|
|
196
219
|
}
|
|
197
220
|
`;
|
|
198
|
-
const StyledBarChart = styled(charts.BarChart).withConfig({ displayName: "StyledBarChart", componentId: "sc-
|
|
221
|
+
const StyledBarChart = styled(charts.BarChart).withConfig({ displayName: "StyledBarChart", componentId: "sc-1l1kx80" }) `
|
|
199
222
|
.domain {
|
|
200
223
|
display: none;
|
|
201
224
|
}
|
|
@@ -7632,30 +7655,33 @@ const useRenderElement = (type = exports.WidgetType.Dashboard, elementConfig) =>
|
|
|
7632
7655
|
]);
|
|
7633
7656
|
};
|
|
7634
7657
|
|
|
7658
|
+
/** Пустой бокс на отключённом пути — стабильная ссылка, чтобы не плодить ре-рендеры. */
|
|
7659
|
+
const EMPTY_BOX = {};
|
|
7635
7660
|
/**
|
|
7636
|
-
* Измеряет
|
|
7661
|
+
* Измеряет фактические ширину и высоту DOM-элемента и обновляет их на любой ресайз (ResizeObserver).
|
|
7637
7662
|
*
|
|
7638
|
-
* Возвращает `[ref,
|
|
7639
|
-
* не измерен. Используется для «резинового» графика: d3-графикам
|
|
7640
|
-
*
|
|
7663
|
+
* Возвращает `[ref, box]`, где `box` — `{ width, height }` в пикселях (content-box) либо пустой объект,
|
|
7664
|
+
* пока элемент ещё не измерен. Используется для «резинового» графика: d3-графикам нужны конкретные
|
|
7665
|
+
* пиксельные размеры, а не CSS `100%`, а для вписывания (fit) нужны обе оси.
|
|
7641
7666
|
*
|
|
7642
7667
|
* `enabled: false` полностью отключает наблюдение — обычные (не fill) графики не измеряются
|
|
7643
7668
|
* и не вызывают лишних ре-рендеров.
|
|
7644
7669
|
*/
|
|
7645
|
-
const
|
|
7670
|
+
const useResizeBox = (enabled) => {
|
|
7646
7671
|
const ref = React.useRef(null);
|
|
7647
|
-
const [
|
|
7672
|
+
const [box, setBox] = React.useState(EMPTY_BOX);
|
|
7648
7673
|
React.useEffect(() => {
|
|
7649
7674
|
const node = ref.current;
|
|
7650
7675
|
if (!enabled || !node)
|
|
7651
7676
|
return;
|
|
7652
7677
|
const observer = new ResizeObserver(([entry]) => {
|
|
7653
|
-
|
|
7678
|
+
const { width, height } = entry.contentRect;
|
|
7679
|
+
setBox({ width, height });
|
|
7654
7680
|
});
|
|
7655
7681
|
observer.observe(node);
|
|
7656
7682
|
return () => observer.disconnect();
|
|
7657
7683
|
}, [enabled]);
|
|
7658
|
-
return [ref, enabled ?
|
|
7684
|
+
return [ref, enabled ? box : EMPTY_BOX];
|
|
7659
7685
|
};
|
|
7660
7686
|
|
|
7661
7687
|
const useShownOtherItems = (options) => {
|
|
@@ -7777,6 +7803,19 @@ const ContainerChart = styled(uilibGl.Flex).withConfig({ displayName: "Container
|
|
|
7777
7803
|
justify-content: center;
|
|
7778
7804
|
width: 100%;
|
|
7779
7805
|
}
|
|
7806
|
+
|
|
7807
|
+
/* fill: слот забирает остаток высоты ячейки (под слотами title/alias/legend) и центрирует тело графика. */
|
|
7808
|
+
${({ $fill }) => $fill &&
|
|
7809
|
+
styled.css `
|
|
7810
|
+
flex: 1 1 auto;
|
|
7811
|
+
min-height: 0;
|
|
7812
|
+
align-items: center;
|
|
7813
|
+
justify-content: center;
|
|
7814
|
+
|
|
7815
|
+
> * {
|
|
7816
|
+
height: 100%;
|
|
7817
|
+
}
|
|
7818
|
+
`}
|
|
7780
7819
|
`;
|
|
7781
7820
|
const ContainerLegend = styled(uilibGl.Flex).withConfig({ displayName: "ContainerLegend", componentId: "sc-z1n1s8" }) ``;
|
|
7782
7821
|
const ContainerUnits = styled.div.withConfig({ displayName: "ContainerUnits", componentId: "sc-1vurgy9" }) `
|
|
@@ -7792,6 +7831,13 @@ const ContainerValue = styled(uilibGl.Flex).withConfig({ displayName: "Container
|
|
|
7792
7831
|
font-size: ${({ big }) => (big ? 1.5 : 1)}rem;
|
|
7793
7832
|
color: ${({ fontColor, theme: { palette } }) => fontColor || palette.textPrimary};
|
|
7794
7833
|
|
|
7834
|
+
/* fill: строка со слотом chart+legend забирает остаток высоты Container'а (гейт — только у Chart-контейнера). */
|
|
7835
|
+
${({ $fill }) => $fill &&
|
|
7836
|
+
styled.css `
|
|
7837
|
+
flex: 1 1 auto;
|
|
7838
|
+
min-height: 0;
|
|
7839
|
+
`}
|
|
7840
|
+
|
|
7795
7841
|
> * {
|
|
7796
7842
|
width: ${({ column }) => (column ? "100%" : "auto")};
|
|
7797
7843
|
}
|
|
@@ -8423,6 +8469,10 @@ const ChartContainerWrapper = styled(uilibGl.FlexSpan).withConfig({ displayName:
|
|
|
8423
8469
|
/* Заданная высота контейнера достаётся телу графика — за вычетом заголовка. */
|
|
8424
8470
|
${({ $sizeCss }) => !!$sizeCss?.height &&
|
|
8425
8471
|
styled.css `
|
|
8472
|
+
/* Раздача высоты требует, чтобы обёртка была flex-колонкой (FlexSpan сам по себе не flex),
|
|
8473
|
+
иначе Container с flex:1 1 auto не растянется на заданную высоту, а fill-график не впишется по высоте. */
|
|
8474
|
+
display: flex;
|
|
8475
|
+
|
|
8426
8476
|
> ${Container} {
|
|
8427
8477
|
flex: 1 1 auto;
|
|
8428
8478
|
min-height: 0;
|
|
@@ -8433,17 +8483,19 @@ const ChartContainerWrapper = styled(uilibGl.FlexSpan).withConfig({ displayName:
|
|
|
8433
8483
|
`;
|
|
8434
8484
|
|
|
8435
8485
|
/**
|
|
8436
|
-
*
|
|
8486
|
+
* Контекст вписывания графика (`options.fill` контейнера Chart).
|
|
8437
8487
|
*
|
|
8438
8488
|
* Компонент `Chart` рендерится через `renderElement({ id: "chart" })` и получает только дочерний
|
|
8439
8489
|
* узел `{ id: "chart" }` — опции контейнера до него не доходят. `ChartContainer` оборачивает
|
|
8440
|
-
* график в провайдер этого контекста, а `Chart` читает
|
|
8490
|
+
* график в провайдер этого контекста, а `Chart` читает значение через `useContext`.
|
|
8441
8491
|
*/
|
|
8442
|
-
const
|
|
8492
|
+
const FillContext = React.createContext({ fill: false, fitHeight: false });
|
|
8443
8493
|
|
|
8444
8494
|
const ChartContainer = React.memo(({ elementConfig, isVisible, type, renderElement }) => {
|
|
8445
8495
|
const { options, children } = elementConfig || {};
|
|
8446
|
-
const { twoColumns, hideEmpty,
|
|
8496
|
+
const { twoColumns, hideEmpty, height } = options || {};
|
|
8497
|
+
const fill = options?.fill;
|
|
8498
|
+
const fillContextValue = React.useMemo(() => ({ fill: !!fill, fitHeight: !!fill && height != null }), [fill, height]);
|
|
8447
8499
|
const aliasElement = children.find(child => child.id === "alias");
|
|
8448
8500
|
const chartElement = children.find(child => child.id === "chart");
|
|
8449
8501
|
const legendElement = children.find(child => child.id === "legend");
|
|
@@ -8458,7 +8510,7 @@ const ChartContainer = React.memo(({ elementConfig, isVisible, type, renderEleme
|
|
|
8458
8510
|
const hasItems = !!data[0]?.items?.length;
|
|
8459
8511
|
if (!loading && !hasItems && hideEmpty)
|
|
8460
8512
|
return null;
|
|
8461
|
-
return (jsxRuntime.jsxs(ChartContainerWrapper, { ...root, children: [jsxRuntime.jsx(ExpandableTitle, { elementConfig: elementConfig, type: type, renderElement: renderElement }), isVisible && (jsxRuntime.jsxs(Container, { isColumn: true, children: [aliasElement && jsxRuntime.jsx(ContainerAlias, { hasBottomMargin: true, children: renderElement({ id: "alias" }) }), jsxRuntime.jsx(ContainerValue, { column: !twoColumns, alignItems: "center", children: hasItems ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(ContainerChart, { children: jsxRuntime.jsx(
|
|
8513
|
+
return (jsxRuntime.jsxs(ChartContainerWrapper, { ...root, children: [jsxRuntime.jsx(ExpandableTitle, { elementConfig: elementConfig, type: type, renderElement: renderElement }), isVisible && (jsxRuntime.jsxs(Container, { isColumn: true, children: [aliasElement && jsxRuntime.jsx(ContainerAlias, { hasBottomMargin: true, children: renderElement({ id: "alias" }) }), jsxRuntime.jsx(ContainerValue, { column: !twoColumns, alignItems: twoColumns && fill ? "stretch" : "center", "$fill": !!fill, children: hasItems ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(ContainerChart, { "$fill": !!fill, children: jsxRuntime.jsx(FillContext.Provider, { value: fillContextValue, children: renderElement({ id: "chart" }) }) }), jsxRuntime.jsx(ContainerLegend, { justifyContent: legendElement?.options?.center ? "center" : "flex-start", children: renderElement({ id: "legend" }) })] })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: "\u2014" })) })] }))] }));
|
|
8462
8514
|
});
|
|
8463
8515
|
|
|
8464
8516
|
const PagesContainer = React.memo(({ type = exports.WidgetType.Dashboard, noBorders }) => {
|
|
@@ -11465,6 +11517,8 @@ const tagTypography = (tag) => ({ $typography }) => {
|
|
|
11465
11517
|
${style.fontSize && `font-size: ${style.fontSize};`}
|
|
11466
11518
|
${style.lineHeight && `line-height: ${style.lineHeight};`}
|
|
11467
11519
|
${style.fontWeight != null && `font-weight: ${style.fontWeight};`}
|
|
11520
|
+
${style.marginTop && `margin-top: ${style.marginTop};`}
|
|
11521
|
+
${style.marginBottom && `margin-bottom: ${style.marginBottom};`}
|
|
11468
11522
|
`;
|
|
11469
11523
|
};
|
|
11470
11524
|
const MarkdownWrapper = styled.div.withConfig({ displayName: "MarkdownWrapper", componentId: "sc-1iv8z8a" }) `
|
|
@@ -12697,7 +12751,8 @@ const ChartLoading = ({ column }) => (jsxRuntime.jsx(uilibGl.Flex, { position: "
|
|
|
12697
12751
|
|
|
12698
12752
|
const ContainerLoading = () => (jsxRuntime.jsx(uilibGl.Flex, { alignContent: "center", justifyContent: "center", width: "100%", children: jsxRuntime.jsx(uilibGl.CircularProgress, { diameter: 1.5, mono: true }) }));
|
|
12699
12753
|
|
|
12700
|
-
// forwardRef
|
|
12754
|
+
// forwardRef сохранён для совместимости; в fill-режиме ResizeObserver меряет внешнюю обёртку
|
|
12755
|
+
// ChartFillMeasure (см. Chart/index.tsx), а не сам ChartWrapper.
|
|
12701
12756
|
const ChartWrapper = React.memo(React.forwardRef(({ width, height, column, loading, children }, ref) => {
|
|
12702
12757
|
return (jsxRuntime.jsxs(ChartWrapperContainer, { ref: ref, column: column, style: { width, height }, children: [loading && jsxRuntime.jsx(ChartLoading, { column: column }), jsxRuntime.jsx(uilibGl.Flex, { opacity: loading ? FILTERED_VALUE_OPACITY / 100 : 1, children: children })] }));
|
|
12703
12758
|
}));
|
|
@@ -14034,10 +14089,10 @@ const Chart = React.memo(({ config, element, elementConfig, type, renderElement
|
|
|
14034
14089
|
const primaryColor = palette.primary;
|
|
14035
14090
|
const { t } = useGlobalContext();
|
|
14036
14091
|
const { expandedContainers, attributes, dataSources } = useWidgetContext(type);
|
|
14037
|
-
//
|
|
14038
|
-
// т.к. d3-графики (и useChartChange для line) требуют
|
|
14039
|
-
const fill = React.useContext(
|
|
14040
|
-
const [chartRef, measuredWidth] =
|
|
14092
|
+
// fill контейнера: вписываем тело графика в контейнер. Размеры ячейки измеряем реально (ResizeObserver),
|
|
14093
|
+
// т.к. d3-графики (и useChartChange для line) требуют пиксельные числа, а не CSS "100%".
|
|
14094
|
+
const { fill, fitHeight } = React.useContext(FillContext);
|
|
14095
|
+
const [chartRef, { width: measuredWidth, height: measuredHeight }] = useResizeBox(fill);
|
|
14041
14096
|
const { id, options, children } = element || {};
|
|
14042
14097
|
const { column, markers: configMarkers, showLabels, showMarkers, showTotal, totalWord: configTotalWord, totalAttribute, expandable, expanded, chartType, relatedDataSources, defaultColor, dotSnapping, } = options || {};
|
|
14043
14098
|
const isLineChart = chartType === "line";
|
|
@@ -14073,11 +14128,19 @@ const Chart = React.memo(({ config, element, elementConfig, type, renderElement
|
|
|
14073
14128
|
const chartWidth = fill
|
|
14074
14129
|
? measuredWidth ?? DEFAULT_CHART_WIDTH
|
|
14075
14130
|
: toPxNumber(width) ?? DEFAULT_CHART_WIDTH;
|
|
14131
|
+
// Фит по высоте включается только при заданной высоте контейнера (fitHeight) и уже измеренной
|
|
14132
|
+
// ячейке; иначе — прежняя фикс. высота options.height. Флаг важен и ниже: он различает два
|
|
14133
|
+
// смысла chartHeight — «высота тела» (вне fill) и «вся доступная высота» (в fill).
|
|
14134
|
+
const fitsHeight = React.useMemo(() => !!(fill && fitHeight && measuredHeight), [fill, fitHeight, measuredHeight]);
|
|
14135
|
+
// fill по высоте: тянем тело графика на измеренную доступную высоту ячейки (content-box минус слоты).
|
|
14136
|
+
const chartHeight = React.useMemo(() => (fitsHeight && measuredHeight ? measuredHeight : height), [fitsHeight, measuredHeight, height]);
|
|
14137
|
+
// Круглый график вписываем по короткой стороне (object-fit: contain), центрируя в ячейке.
|
|
14138
|
+
const pieSide = React.useMemo(() => (fitsHeight && measuredHeight ? Math.min(chartWidth, measuredHeight) : chartWidth), [fitsHeight, measuredHeight, chartWidth]);
|
|
14076
14139
|
const [customize] = useChartChange({
|
|
14077
14140
|
dataSources: config.dataSources,
|
|
14078
14141
|
chartId: elementConfig?.id,
|
|
14079
14142
|
width: chartWidth,
|
|
14080
|
-
height,
|
|
14143
|
+
height: chartHeight,
|
|
14081
14144
|
fontColor,
|
|
14082
14145
|
relatedAttributes,
|
|
14083
14146
|
defaultColor: primaryColor,
|
|
@@ -14177,26 +14240,37 @@ const Chart = React.memo(({ config, element, elementConfig, type, renderElement
|
|
|
14177
14240
|
.flat()
|
|
14178
14241
|
.map(({ values }) => values)
|
|
14179
14242
|
.flat();
|
|
14180
|
-
return (jsxRuntime.jsxs(AnyChartWrapper, { height:
|
|
14243
|
+
return (jsxRuntime.jsxs(AnyChartWrapper, { height: chartHeight, children: [jsxRuntime.jsx(LineChartStyles, {}), jsxRuntime.jsx(charts.LineChart, { data: lineChartData, labels: labels, markers: markers, width: chartWidth, height: chartHeight, xAxisPadding: 15, yAxisPadding: 0, min: Math.min(...chartValues), customYAxisSelection: yAxis => {
|
|
14181
14244
|
if (isHidedY) {
|
|
14182
14245
|
yAxis.remove();
|
|
14183
14246
|
}
|
|
14184
14247
|
}, customYAxis: yAxis => yAxis.ticks(4), renderTooltip: renderLineChartTooltip, customize: customize, dotSnapping: dotSnapping, dynamicTooltipEnable: true, stackedTooltip: true, tooltipClassName: "dashboardLineChartTooltip", drawGridX: !isHidedY, margin: margin })] }));
|
|
14185
14248
|
}
|
|
14186
14249
|
if (isStackBar) {
|
|
14187
|
-
|
|
14250
|
+
// Вне fill chartHeight — высота самой полосы, и обёртка честно становится выше на строку
|
|
14251
|
+
// итога. В fill chartHeight — уже ВСЯ доступная высота ячейки, поэтому строку итога надо
|
|
14252
|
+
// вычесть из неё (обёртка остаётся ровно по ячейке), а не прибавить сверху — иначе тело
|
|
14253
|
+
// вылезает за нижнюю границу на STACK_BAR_TOTAL_HEIGHT.
|
|
14254
|
+
const stackBarHeight = showTotal && !fitsHeight ? chartHeight + STACK_BAR_TOTAL_HEIGHT : chartHeight;
|
|
14188
14255
|
return (jsxRuntime.jsx(AnyChartWrapper, { height: stackBarHeight, children: jsxRuntime.jsx(StackBar, { data: data, filterName: filterName, type: type, alias: elementConfig?.children?.find(child => child.id === "alias"), options: options, renderTooltip: renderPieChartTooltip, renderElement: renderElement }) }));
|
|
14189
14256
|
}
|
|
14190
14257
|
if (isPieChart) {
|
|
14191
|
-
return (jsxRuntime.jsx(AnyChartWrapper, { height: height, children: jsxRuntime.jsx(charts.PieChart, { data: (data[0]?.items
|
|
14258
|
+
return (jsxRuntime.jsx(AnyChartWrapper, { height: fill ? pieSide : height, children: jsxRuntime.jsx(charts.PieChart, { data: (data[0]?.items
|
|
14192
14259
|
?.filter(({ value }) => !isEmptyValue(value))
|
|
14193
14260
|
?.map(item => ({
|
|
14194
14261
|
...item,
|
|
14195
14262
|
color: formatFilterColor(item.name, item.color, defaultColor),
|
|
14196
|
-
})) || []), width:
|
|
14263
|
+
})) || []), width: pieSide, height: pieSide, padAngle: angle, outerRadius: radius, cornerRadius: cornerRadius, renderTooltip: renderPieChartTooltip, withTooltip: true, onClick: filterName ? item => onFilter(item.name) : undefined, children: showTotal && (jsxRuntime.jsx(PieChartCenter, { children: totalWord || roundTotalSum(+totalSum) })) }) }));
|
|
14197
14264
|
}
|
|
14198
14265
|
const barChartData = getDataFromFilterItems(data[0]?.items);
|
|
14199
|
-
|
|
14266
|
+
// Тот же случай, что у stack: обёртка выше тела на подписи оси X (margin.bottom). В fill
|
|
14267
|
+
// chartHeight — вся доступная высота, поэтому подписи вычитаем из неё, а не прибавляем.
|
|
14268
|
+
// BAR_CHART_FOOTER_MARGIN — это внешний margin-bottom самой BarChartWrapper: в её height он
|
|
14269
|
+
// не входит, но место в ячейке занимает, поэтому его тоже вычитаем.
|
|
14270
|
+
const barBodyHeight = fitsHeight
|
|
14271
|
+
? chartHeight - margin.bottom - BAR_CHART_FOOTER_MARGIN
|
|
14272
|
+
: chartHeight;
|
|
14273
|
+
return (jsxRuntime.jsx(BarChartWrapper, { height: barBodyHeight + margin.bottom, children: jsxRuntime.jsx(BarChartContainer, { children: jsxRuntime.jsx(StyledBarChart, { data: barChartData, colors: getColorsFromFilterItems(data[0]?.items, defaultColor, formatFilterColor), minValue: getMinValueFromFilterItems(data[0]?.items), markers: markers, width: chartWidth, height: barBodyHeight, barWidth: barWidth, barPadding: padding, customYAxisLeft: customYAxisLeft, customXAxisBottom: xAxisBottom => customXAxisBottom(xAxisBottom, barChartData), customYAxis: axis => !showLabels && axis.remove(), customBars: ({ bars }) => {
|
|
14200
14274
|
bars.attr("rx", radius);
|
|
14201
14275
|
bars.attr("ry", radius);
|
|
14202
14276
|
}, margin: margin, xAxisPadding: 0, yAxisPadding: 0, formatTooltipValue: formatTooltipValue, formatTooltipName: formatTooltipName, hideTooltipGroupName: true, dynamicTooltipEnable: true, isBarTooltip: true, onBarClick: filterName ? item => onFilter(item.name) : undefined }) }) }));
|
|
@@ -14214,6 +14288,10 @@ const Chart = React.memo(({ config, element, elementConfig, type, renderElement
|
|
|
14214
14288
|
defaultColor,
|
|
14215
14289
|
formatFilterColor,
|
|
14216
14290
|
chartWidth,
|
|
14291
|
+
chartHeight,
|
|
14292
|
+
fitsHeight,
|
|
14293
|
+
pieSide,
|
|
14294
|
+
fill,
|
|
14217
14295
|
barWidth,
|
|
14218
14296
|
showLabels,
|
|
14219
14297
|
padding,
|
|
@@ -14241,7 +14319,11 @@ const Chart = React.memo(({ config, element, elementConfig, type, renderElement
|
|
|
14241
14319
|
]);
|
|
14242
14320
|
if (!isVisibleContainer(id, expandable, expanded, expandedContainers))
|
|
14243
14321
|
return null;
|
|
14244
|
-
|
|
14322
|
+
const chartBody = (jsxRuntime.jsx(ChartWrapper, { width: isPieChart && fill ? pieSide : width, height: isStackBar ? "auto" : isPieChart ? (fill ? pieSide : width) : chartHeight, column: column, loading: loading, children: renderChart }));
|
|
14323
|
+
if (!fill)
|
|
14324
|
+
return chartBody;
|
|
14325
|
+
// fill: тело центрируется в измеряемой обёртке, ref которой питает ResizeObserver обеими осями.
|
|
14326
|
+
return jsxRuntime.jsx(ChartFillMeasure, { ref: chartRef, children: chartBody });
|
|
14245
14327
|
});
|
|
14246
14328
|
|
|
14247
14329
|
const ChartLegend = ({ data, chartElement, fontSize, type, twoColumns, loading }) => {
|
|
@@ -15298,7 +15380,7 @@ exports.useRedrawLayer = useRedrawLayer;
|
|
|
15298
15380
|
exports.useRelatedDataSourceAttributes = useRelatedDataSourceAttributes;
|
|
15299
15381
|
exports.useRemoteTask = useRemoteTask;
|
|
15300
15382
|
exports.useRenderElement = useRenderElement;
|
|
15301
|
-
exports.
|
|
15383
|
+
exports.useResizeBox = useResizeBox;
|
|
15302
15384
|
exports.useSavePrototypeBuilder = useSavePrototypeBuilder;
|
|
15303
15385
|
exports.useServerNotificationsContext = useServerNotificationsContext;
|
|
15304
15386
|
exports.useShownOtherItems = useShownOtherItems;
|