mdt-charts 1.20.0 → 1.20.1
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/lib/config/config.d.ts +14 -0
- package/lib/engine/block/blockSvg.d.ts +1 -1
- package/lib/engine/block/blockSvg.js +1 -1
- package/lib/engine/elementHighlighter/elementHighlighter.d.ts +0 -1
- package/lib/engine/elementHighlighter/elementHighlighter.js +5 -8
- package/lib/engine/elementHighlighter/selectHighlighter.js +11 -10
- package/lib/engine/features/legend/legendMarkerCreator.js +1 -1
- package/lib/engine/features/markDots/markDot.d.ts +11 -3
- package/lib/engine/features/markDots/markDot.js +21 -10
- package/lib/engine/features/tolltip/tooltip.js +5 -4
- package/lib/engine/features/valueLabels/valueLabels.d.ts +45 -0
- package/lib/engine/features/valueLabels/valueLabels.js +139 -0
- package/lib/engine/features/valueLabels/valueLabelsHelper.d.ts +6 -0
- package/lib/engine/features/valueLabels/valueLabelsHelper.js +21 -0
- package/lib/engine/features/valueLabelsCollision/valueLabelsCollision.d.ts +23 -0
- package/lib/engine/features/valueLabelsCollision/valueLabelsCollision.js +24 -0
- package/lib/engine/features/valueLabelsCollision/valueLabelsCollisionHelper.d.ts +5 -0
- package/lib/engine/features/valueLabelsCollision/valueLabelsCollisionHelper.js +47 -0
- package/lib/engine/twoDimensionalNotation/area/area.d.ts +18 -11
- package/lib/engine/twoDimensionalNotation/area/area.js +32 -22
- package/lib/engine/twoDimensionalNotation/area/areaGenerator.d.ts +14 -0
- package/lib/engine/twoDimensionalNotation/area/areaGenerator.js +22 -0
- package/lib/engine/twoDimensionalNotation/area/areaHelper.d.ts +7 -7
- package/lib/engine/twoDimensionalNotation/area/areaHelper.js +30 -31
- package/lib/engine/twoDimensionalNotation/bar/barHelper.js +1 -1
- package/lib/engine/twoDimensionalNotation/bar/stackedData/dataStacker.d.ts +4 -2
- package/lib/engine/twoDimensionalNotation/bar/stackedData/dataStacker.js +2 -5
- package/lib/engine/twoDimensionalNotation/line/line.d.ts +0 -6
- package/lib/engine/twoDimensionalNotation/line/line.js +4 -4
- package/lib/engine/twoDimensionalNotation/line/lineGenerator.d.ts +4 -7
- package/lib/engine/twoDimensionalNotation/line/lineGenerator.js +2 -16
- package/lib/engine/twoDimensionalNotation/line/lineHelper.d.ts +4 -13
- package/lib/engine/twoDimensionalNotation/line/lineHelper.js +22 -10
- package/lib/engine/twoDimensionalNotation/lineLike/generatorFactory/lineLikeGeneratorFactory.d.ts +12 -0
- package/lib/engine/twoDimensionalNotation/lineLike/generatorFactory/lineLikeGeneratorFactory.js +1 -0
- package/lib/engine/twoDimensionalNotation/lineLike/generatorMiddleware/lineLikeGeneratorCurveMiddleware.d.ts +14 -0
- package/lib/engine/twoDimensionalNotation/lineLike/generatorMiddleware/lineLikeGeneratorCurveMiddleware.js +21 -0
- package/lib/engine/twoDimensionalNotation/lineLike/generatorMiddleware/lineLikeGeneratorDefineMiddleware.d.ts +20 -0
- package/lib/engine/twoDimensionalNotation/lineLike/generatorMiddleware/lineLikeGeneratorDefineMiddleware.js +9 -0
- package/lib/engine/twoDimensionalNotation/lineLike/generatorMiddleware/lineLikeGeneratorMiddleware.d.ts +5 -0
- package/lib/engine/twoDimensionalNotation/lineLike/generatorMiddleware/lineLikeGeneratorMiddleware.js +1 -0
- package/lib/engine/twoDimensionalNotation/twoDimensionalManager.d.ts +1 -0
- package/lib/engine/twoDimensionalNotation/twoDimensionalManager.js +19 -3
- package/lib/model/featuresModel/axisModel.js +3 -1
- package/lib/model/featuresModel/valueLabelsModel/valueLabelsModel.d.ts +9 -0
- package/lib/model/featuresModel/valueLabelsModel/valueLabelsModel.js +33 -0
- package/lib/model/helpers/modelHelper.d.ts +1 -0
- package/lib/model/helpers/modelHelper.js +3 -2
- package/lib/model/helpers/twoDimensionalModelHelper.d.ts +5 -0
- package/lib/model/helpers/twoDimensionalModelHelper.js +16 -0
- package/lib/model/model.d.ts +28 -5
- package/lib/model/modelInstance/configReader.d.ts +2 -1
- package/lib/model/modelInstance/configReader.js +17 -0
- package/lib/model/notations/twoDimensionalModel.js +24 -24
- package/package.json +1 -1
- /package/lib/engine/block/{defs.d.ts → defs/hatchPattern.d.ts} +0 -0
- /package/lib/engine/block/{defs.js → defs/hatchPattern.js} +0 -0
package/lib/config/config.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export declare type TwoDimensionalChartType = 'line' | 'bar' | 'area';
|
|
|
8
8
|
export declare type PolarChartType = 'donut';
|
|
9
9
|
export declare type IntervalChartType = 'gantt';
|
|
10
10
|
export declare type EmbeddedLabelType = 'none' | 'key' | 'value';
|
|
11
|
+
export declare type ValueLabelsCollisionMode = "none" | "hide";
|
|
11
12
|
export declare type MdtChartsDataRow = {
|
|
12
13
|
[field: string]: any;
|
|
13
14
|
};
|
|
@@ -53,6 +54,7 @@ export interface MdtChartsTwoDimensionalOptions extends GraphicNotationOptions {
|
|
|
53
54
|
additionalElements: AdditionalElements;
|
|
54
55
|
charts: MdtChartsTwoDimensionalChart[];
|
|
55
56
|
orientation: ChartOrientation;
|
|
57
|
+
valueLabels?: TwoDimensionalValueLabels;
|
|
56
58
|
}
|
|
57
59
|
export interface MdtChartsPolarOptions extends GraphicNotationOptions {
|
|
58
60
|
type: 'polar';
|
|
@@ -172,6 +174,12 @@ export interface MdtChartsShowAxisLabelRule {
|
|
|
172
174
|
spaceForOneLabel?: number;
|
|
173
175
|
showTickFn?: ShowTickFn;
|
|
174
176
|
}
|
|
177
|
+
export interface TwoDimensionalValueLabels {
|
|
178
|
+
collision: ValueLabelsCollision;
|
|
179
|
+
}
|
|
180
|
+
export interface ValueLabelsCollision {
|
|
181
|
+
mode: ValueLabelsCollisionMode;
|
|
182
|
+
}
|
|
175
183
|
export interface IntervalAxis {
|
|
176
184
|
key: DiscreteAxisOptions;
|
|
177
185
|
value: DateAxisOptions;
|
|
@@ -210,6 +218,7 @@ export interface MdtChartsTwoDimensionalChart extends ChartSettings, MdtChartsLi
|
|
|
210
218
|
data: TwoDimensionalChartData;
|
|
211
219
|
embeddedLabels: EmbeddedLabelType;
|
|
212
220
|
isSegmented: boolean;
|
|
221
|
+
valueLabels?: TwoDimensionalChartValueLabels;
|
|
213
222
|
}
|
|
214
223
|
export interface PolarChart extends ChartSettings {
|
|
215
224
|
type: PolarChartType;
|
|
@@ -224,6 +233,11 @@ export interface TwoDimensionalChartData {
|
|
|
224
233
|
valueFields: TwoDimValueField[];
|
|
225
234
|
valueGroup?: TwoDimensionalValueGroup;
|
|
226
235
|
}
|
|
236
|
+
export interface TwoDimensionalChartValueLabels {
|
|
237
|
+
on: boolean;
|
|
238
|
+
format?: ValueLabelsFormatter;
|
|
239
|
+
}
|
|
240
|
+
export declare type ValueLabelsFormatter = (value: number) => string;
|
|
227
241
|
export declare type TwoDimensionalValueGroup = 'main' | 'secondary';
|
|
228
242
|
interface MarkersOptions {
|
|
229
243
|
show: boolean;
|
|
@@ -23,6 +23,6 @@ export declare class BlockSvg {
|
|
|
23
23
|
renderChartClipPath(margin: BlockMargin, blockSize: Size): void;
|
|
24
24
|
updateChartClipPath(margin: BlockMargin, blockSize: Size): void;
|
|
25
25
|
renderBarHatchPattern(): void;
|
|
26
|
-
|
|
26
|
+
ensureDefsRendered(): Selection<SVGDefsElement, unknown, HTMLElement, unknown>;
|
|
27
27
|
}
|
|
28
28
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NamesHelper } from "../helpers/namesHelper";
|
|
2
2
|
import { BlockHelper } from "./blockHelper";
|
|
3
|
-
import { HatchPatternDef } from "./defs";
|
|
3
|
+
import { HatchPatternDef } from "./defs/hatchPattern";
|
|
4
4
|
export class BlockSvg {
|
|
5
5
|
constructor(options) {
|
|
6
6
|
this.hatchPatternDef = new HatchPatternDef();
|
|
@@ -18,7 +18,6 @@ export declare class ElementHighlighter {
|
|
|
18
18
|
static toggleDonutHighlightState(segment: Selection<SVGGElement, PieArcDatum<MdtChartsDataRow>, BaseType, unknown>, margin: BlockMargin, blockSize: Size, donutThickness: number, transitionDuration: number, on: boolean): Promise<any>;
|
|
19
19
|
static removeDonutHighlightingByKeys(arcSegments: Selection<SVGGElement, PieArcDatum<MdtChartsDataRow>, BaseType, unknown>, keyFieldName: string, keyValues: string[], margin: BlockMargin, blockSize: Size, donutThickness: number): void;
|
|
20
20
|
static setInactiveFor2D(block: Block, keyFieldName: string, charts: TwoDimensionalChartModel[]): void;
|
|
21
|
-
static toggleMarkDotVisible(markDots: Selection<BaseType, any, BaseType, any>, isHighlight: boolean): void;
|
|
22
21
|
static remove2DChartsFullHighlighting(block: Block, charts: TwoDimensionalChartModel[], transitionDuration?: number): void;
|
|
23
22
|
static removeUnselected2DHighlight(block: Block, keyFieldName: string, charts: TwoDimensionalChartModel[], transitionDuration: number): void;
|
|
24
23
|
static toggle2DElements(elemSelection: Selection<BaseType, any, BaseType, any>, isHighlight: boolean, chart: TwoDimensionalChartModel, transitionDuration: number): void;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { select } from 'd3-selection';
|
|
2
2
|
import { easeLinear } from 'd3-ease';
|
|
3
3
|
import { interrupt } from 'd3-transition';
|
|
4
|
-
import { DonutHelper } from '../polarNotation/donut/DonutHelper';
|
|
5
4
|
import { DomHelper, SelectionCondition } from '../helpers/domHelper';
|
|
6
5
|
import { Donut } from '../polarNotation/donut/donut';
|
|
7
6
|
import { MarkDot } from '../features/markDots/markDot';
|
|
8
7
|
import { Helper } from '../helpers/helper';
|
|
9
8
|
import * as chroma from 'chroma-js';
|
|
10
9
|
import { NamesHelper } from '../helpers/namesHelper';
|
|
10
|
+
import { DonutHelper } from '../polarNotation/donut/DonutHelper';
|
|
11
11
|
export class ElementHighlighter {
|
|
12
12
|
static toggleActivityStyle(elementSelection, isActive) {
|
|
13
13
|
elementSelection.classed(this.inactiveElemClass, !isActive);
|
|
@@ -86,14 +86,11 @@ export class ElementHighlighter {
|
|
|
86
86
|
}
|
|
87
87
|
});
|
|
88
88
|
}
|
|
89
|
-
static toggleMarkDotVisible(markDots, isHighlight) {
|
|
90
|
-
markDots.classed(MarkDot.hiddenDotClass, !isHighlight);
|
|
91
|
-
}
|
|
92
89
|
static remove2DChartsFullHighlighting(block, charts, transitionDuration = 0) {
|
|
93
90
|
charts.forEach(chart => {
|
|
94
91
|
const elems = DomHelper.get2DChartElements(block, chart);
|
|
95
|
-
if (chart.type !== 'bar'
|
|
96
|
-
|
|
92
|
+
if (chart.type !== 'bar')
|
|
93
|
+
MarkDot.tryMakeMarkDotVisible(elems, chart.markersOptions, false);
|
|
97
94
|
this.toggle2DElements(elems, false, chart, transitionDuration);
|
|
98
95
|
this.toggleActivityStyle(elems, true);
|
|
99
96
|
});
|
|
@@ -102,8 +99,8 @@ export class ElementHighlighter {
|
|
|
102
99
|
charts.forEach(chart => {
|
|
103
100
|
const elems = DomHelper.get2DChartElements(block, chart);
|
|
104
101
|
const selectedElems = DomHelper.getChartElementsByKeys(elems, chart.isSegmented, keyFieldName, block.filterEventManager.getSelectedKeys(), SelectionCondition.Exclude);
|
|
105
|
-
if (chart.type !== 'bar'
|
|
106
|
-
|
|
102
|
+
if (chart.type !== 'bar')
|
|
103
|
+
MarkDot.tryMakeMarkDotVisible(selectedElems, chart.markersOptions, false);
|
|
107
104
|
this.toggle2DElements(selectedElems, false, chart, transitionDuration);
|
|
108
105
|
if (block.filterEventManager.getSelectedKeys().length > 0)
|
|
109
106
|
this.toggleActivityStyle(selectedElems, false);
|
|
@@ -4,6 +4,7 @@ import { DomHelper, SelectionCondition } from "../helpers/domHelper";
|
|
|
4
4
|
import { Donut } from "../polarNotation/donut/donut";
|
|
5
5
|
import { DonutHelper } from "../polarNotation/donut/DonutHelper";
|
|
6
6
|
import { ElementHighlighter } from "./elementHighlighter";
|
|
7
|
+
import { MarkDot } from "../../engine/features/markDots/markDot";
|
|
7
8
|
export class SelectHighlighter {
|
|
8
9
|
static click2DHandler(multySelection, appendKey, keyValue, selectedKeys, block, options) {
|
|
9
10
|
options.charts.forEach(chart => {
|
|
@@ -11,15 +12,15 @@ export class SelectHighlighter {
|
|
|
11
12
|
const elements = DomHelper.get2DChartElements(block, chart);
|
|
12
13
|
if (!appendKey) {
|
|
13
14
|
ElementHighlighter.toggle2DElements(selectedElements, false, chart, block.transitionManager.durations.markerHover);
|
|
14
|
-
if (chart.type !== 'bar'
|
|
15
|
-
|
|
15
|
+
if (chart.type !== 'bar')
|
|
16
|
+
MarkDot.tryMakeMarkDotVisible(selectedElements, chart.markersOptions, false);
|
|
16
17
|
if (selectedKeys.length > 0) {
|
|
17
18
|
ElementHighlighter.toggleActivityStyle(selectedElements, false);
|
|
18
19
|
}
|
|
19
20
|
else {
|
|
20
21
|
ElementHighlighter.toggleActivityStyle(elements, true);
|
|
21
|
-
if (chart.type !== 'bar'
|
|
22
|
-
|
|
22
|
+
if (chart.type !== 'bar')
|
|
23
|
+
MarkDot.tryMakeMarkDotVisible(elements, chart.markersOptions, false);
|
|
23
24
|
}
|
|
24
25
|
return;
|
|
25
26
|
}
|
|
@@ -31,13 +32,13 @@ export class SelectHighlighter {
|
|
|
31
32
|
else {
|
|
32
33
|
ElementHighlighter.toggle2DElements(DomHelper.getChartElementsByKeys(elements, chart.isSegmented, options.data.keyField.name, selectedKeys, SelectionCondition.Exclude), false, chart, block.transitionManager.durations.markerHover);
|
|
33
34
|
ElementHighlighter.toggleActivityStyle(elements, false);
|
|
34
|
-
if (chart.type !== 'bar'
|
|
35
|
-
|
|
35
|
+
if (chart.type !== 'bar')
|
|
36
|
+
MarkDot.tryMakeMarkDotVisible(elements, chart.markersOptions, false);
|
|
36
37
|
ElementHighlighter.toggleActivityStyle(selectedElements, true);
|
|
37
38
|
ElementHighlighter.toggle2DElements(selectedElements, true, chart, block.transitionManager.durations.markerHover);
|
|
38
39
|
}
|
|
39
|
-
if (chart.type !== 'bar'
|
|
40
|
-
|
|
40
|
+
if (chart.type !== 'bar')
|
|
41
|
+
MarkDot.tryMakeMarkDotVisible(selectedElements, chart.markersOptions, true);
|
|
41
42
|
});
|
|
42
43
|
}
|
|
43
44
|
static clickPolarHandler(multySelection, appendKey, selectedSegment, selectedKeys, margin, blockSize, block, options, arcItems, donutSettings) {
|
|
@@ -78,8 +79,8 @@ export class SelectHighlighter {
|
|
|
78
79
|
const elements = DomHelper.get2DChartElements(block, chart);
|
|
79
80
|
ElementHighlighter.toggle2DElements(elements, false, chart, block.transitionManager.durations.markerHover);
|
|
80
81
|
ElementHighlighter.toggleActivityStyle(elements, true);
|
|
81
|
-
if (chart.type !== 'bar'
|
|
82
|
-
|
|
82
|
+
if (chart.type !== 'bar')
|
|
83
|
+
MarkDot.tryMakeMarkDotVisible(elements, chart.markersOptions, false);
|
|
83
84
|
});
|
|
84
85
|
}
|
|
85
86
|
static clearPolar(margin, blockSize, block, options, arcItems, donutSettings) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Legend } from "./legend";
|
|
2
|
-
import { HatchPatternDef } from "../../block/defs";
|
|
2
|
+
import { HatchPatternDef } from "../../block/defs/hatchPattern";
|
|
3
3
|
import { applyLineDash } from "../../twoDimensionalNotation/line/lineHelper";
|
|
4
4
|
export class LegendMarkerCreator {
|
|
5
5
|
create(selection, options) {
|
|
@@ -1,19 +1,27 @@
|
|
|
1
1
|
import { Selection, BaseType } from 'd3-selection';
|
|
2
2
|
import { MdtChartsDataRow } from '../../../config/config';
|
|
3
|
-
import { BlockMargin, Orient, TwoDimensionalChartModel } from "../../../model/model";
|
|
3
|
+
import { BlockMargin, MarkersOptions, Orient, TwoDimensionalChartModel } from "../../../model/model";
|
|
4
4
|
import { Block } from "../../block/block";
|
|
5
5
|
import { Scales } from "../scale/scale";
|
|
6
6
|
export interface DotAttrs {
|
|
7
7
|
cx: (data: MdtChartsDataRow) => number;
|
|
8
8
|
cy: (data: MdtChartsDataRow) => number;
|
|
9
9
|
}
|
|
10
|
+
interface MarkDotDataItem extends MdtChartsDataRow {
|
|
11
|
+
$mdtChartsMetadata: {
|
|
12
|
+
valueFieldName: string;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
10
15
|
export declare class MarkDot {
|
|
11
16
|
static readonly markerDotClass: string;
|
|
12
17
|
static readonly hiddenDotClass: string;
|
|
13
18
|
static render(block: Block, data: MdtChartsDataRow[], keyAxisOrient: Orient, scales: Scales, margin: BlockMargin, keyFieldName: string, vfIndex: number, valueFieldName: string, chart: TwoDimensionalChartModel): void;
|
|
14
|
-
static update(block: Block, newData: MdtChartsDataRow[], keyAxisOrient: Orient, scales: Scales, margin: BlockMargin,
|
|
19
|
+
static update(block: Block, newData: MdtChartsDataRow[], keyAxisOrient: Orient, scales: Scales, margin: BlockMargin, keyFieldName: string, vfIndex: number, valueFieldName: string, chart: TwoDimensionalChartModel): void;
|
|
15
20
|
static updateColors(block: Block, chart: TwoDimensionalChartModel, valueFieldIndex: number): void;
|
|
16
|
-
static getMarkDotForChart(block: Block, chartCssClasses: string[]): Selection<BaseType,
|
|
21
|
+
static getMarkDotForChart(block: Block, chartCssClasses: string[]): Selection<BaseType, MarkDotDataItem, BaseType, unknown>;
|
|
22
|
+
static tryMakeMarkDotVisible(elems: Selection<BaseType, MdtChartsDataRow, BaseType, unknown>, markersOptions: MarkersOptions, turnOnIfCan: boolean): void;
|
|
23
|
+
private static toggleMarkDotVisible;
|
|
17
24
|
private static setClassesAndStyle;
|
|
18
25
|
private static setAttrs;
|
|
19
26
|
}
|
|
27
|
+
export {};
|
|
@@ -9,30 +9,31 @@ export class MarkDot {
|
|
|
9
9
|
static render(block, data, keyAxisOrient, scales, margin, keyFieldName, vfIndex, valueFieldName, chart) {
|
|
10
10
|
const dotsWrapper = block.svg.getChartGroup(chart.index)
|
|
11
11
|
.selectAll(`.${this.markerDotClass}${Helper.getCssClassesLine(chart.cssClasses)}.chart-index-${vfIndex}`)
|
|
12
|
-
.data(data)
|
|
12
|
+
.data(data.map(row => (Object.assign(Object.assign({}, row), { $mdtChartsMetadata: { valueFieldName } }))))
|
|
13
13
|
.enter();
|
|
14
14
|
const attrs = MarkDotHelper.getDotAttrs(keyAxisOrient, scales, margin, keyFieldName, valueFieldName, chart.isSegmented);
|
|
15
15
|
const dots = dotsWrapper.append('circle');
|
|
16
16
|
this.setAttrs(block, dots, attrs, chart.markersOptions.styles);
|
|
17
17
|
this.setClassesAndStyle(dots, chart.cssClasses, vfIndex, chart.style.elementColors);
|
|
18
|
-
|
|
19
|
-
dots.classed(this.hiddenDotClass, true);
|
|
18
|
+
MarkDot.tryMakeMarkDotVisible(dots, chart.markersOptions, false);
|
|
20
19
|
}
|
|
21
|
-
static update(block, newData, keyAxisOrient, scales, margin,
|
|
20
|
+
static update(block, newData, keyAxisOrient, scales, margin, keyFieldName, vfIndex, valueFieldName, chart) {
|
|
22
21
|
const dots = block.svg.getChartGroup(chart.index)
|
|
23
22
|
.selectAll(`.${this.markerDotClass}${Helper.getCssClassesLine(chart.cssClasses)}.chart-element-${vfIndex}`)
|
|
24
|
-
.data(newData);
|
|
23
|
+
.data(newData.map(row => (Object.assign(Object.assign({}, row), { $mdtChartsMetadata: { valueFieldName } }))));
|
|
25
24
|
dots.exit().remove();
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
dots.each(function (datum) {
|
|
26
|
+
if (chart.markersOptions.show({ row: datum, valueFieldName })) {
|
|
27
|
+
MarkDot.toggleMarkDotVisible(select(this), true);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
const attrs = MarkDotHelper.getDotAttrs(keyAxisOrient, scales, margin, keyFieldName, valueFieldName, chart.isSegmented);
|
|
29
31
|
const newDots = dots
|
|
30
32
|
.enter()
|
|
31
33
|
.append('circle');
|
|
32
34
|
this.setAttrs(block, newDots, attrs, chart.markersOptions.styles);
|
|
33
35
|
this.setClassesAndStyle(newDots, chart.cssClasses, vfIndex, chart.style.elementColors);
|
|
34
|
-
|
|
35
|
-
newDots.classed(this.hiddenDotClass, true);
|
|
36
|
+
MarkDot.tryMakeMarkDotVisible(newDots, chart.markersOptions, false);
|
|
36
37
|
const animationName = 'data-updating';
|
|
37
38
|
dots
|
|
38
39
|
.interrupt(animationName)
|
|
@@ -50,6 +51,16 @@ export class MarkDot {
|
|
|
50
51
|
return block.getSvg()
|
|
51
52
|
.selectAll(`.${MarkDot.markerDotClass}${Helper.getCssClassesLine(chartCssClasses)}`);
|
|
52
53
|
}
|
|
54
|
+
static tryMakeMarkDotVisible(elems, markersOptions, turnOnIfCan) {
|
|
55
|
+
elems.each(function (datum) {
|
|
56
|
+
var _a;
|
|
57
|
+
if (!markersOptions.show({ row: datum, valueFieldName: (_a = datum.$mdtChartsMetadata) === null || _a === void 0 ? void 0 : _a.valueFieldName }))
|
|
58
|
+
MarkDot.toggleMarkDotVisible(select(this), turnOnIfCan);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
static toggleMarkDotVisible(markDots, isHighlight) {
|
|
62
|
+
markDots.classed(MarkDot.hiddenDotClass, !isHighlight);
|
|
63
|
+
}
|
|
53
64
|
static setClassesAndStyle(dots, cssClasses, vfIndex, elementColors) {
|
|
54
65
|
DomHelper.setCssClasses(dots, Helper.getCssClassesWithElementIndex(cssClasses, vfIndex));
|
|
55
66
|
DomHelper.setChartElementColor(dots, elementColors, vfIndex, 'stroke');
|
|
@@ -10,6 +10,7 @@ import { Helper } from '../../helpers/helper';
|
|
|
10
10
|
import { TooltipHelper } from './tooltipHelper';
|
|
11
11
|
import { DomHelper } from '../../helpers/domHelper';
|
|
12
12
|
import { NewTooltip } from './newTooltip/newTooltip';
|
|
13
|
+
import { MarkDot } from "../../../engine/features/markDots/markDot";
|
|
13
14
|
export class Tooltip {
|
|
14
15
|
static render(block, model, data, tooltipOptions, scales) {
|
|
15
16
|
TooltipComponentsManager.renderTooltipWrapper(block);
|
|
@@ -79,16 +80,16 @@ export class Tooltip {
|
|
|
79
80
|
const elements = DomHelper.get2DChartElements(block, chart);
|
|
80
81
|
if (!block.filterEventManager.isSelected(currentKey)) {
|
|
81
82
|
const oldElements = DomHelper.getChartElementsByKeys(elements, chart.isSegmented, args.dataOptions.keyField.name, [currentKey]);
|
|
82
|
-
if (chart.type !== 'bar'
|
|
83
|
-
|
|
83
|
+
if (chart.type !== 'bar')
|
|
84
|
+
MarkDot.tryMakeMarkDotVisible(oldElements, chart.markersOptions, false);
|
|
84
85
|
ElementHighlighter.toggle2DElements(oldElements, false, chart, block.transitionManager.durations.markerHover);
|
|
85
86
|
if (block.filterEventManager.getSelectedKeys().length > 0) {
|
|
86
87
|
ElementHighlighter.toggleActivityStyle(oldElements, false);
|
|
87
88
|
}
|
|
88
89
|
}
|
|
89
90
|
const selectedElements = DomHelper.getChartElementsByKeys(elements, chart.isSegmented, args.dataOptions.keyField.name, [keyValue]);
|
|
90
|
-
if (chart.type !== 'bar'
|
|
91
|
-
|
|
91
|
+
if (chart.type !== 'bar')
|
|
92
|
+
MarkDot.tryMakeMarkDotVisible(selectedElements, chart.markersOptions, true);
|
|
92
93
|
ElementHighlighter.toggleActivityStyle(selectedElements, true);
|
|
93
94
|
if (block.filterEventManager.getSelectedKeys().length === 0 || block.filterEventManager.isSelected(keyValue)) {
|
|
94
95
|
ElementHighlighter.toggle2DElements(selectedElements, true, chart, block.transitionManager.durations.markerHover);
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Block } from "../../../engine/block/block";
|
|
2
|
+
import { OptionsModelData, Orient, TwoDimensionalChartModel, TwoDimensionalValueLabels, ValueLabelAnchor, ValueLabelDominantBaseline } from "../../../model/model";
|
|
3
|
+
import { MdtChartsDataRow, MdtChartsDataSource } from "../../../config/config";
|
|
4
|
+
import { Scales, ScalesWithSecondary } from "../../../engine/features/scale/scale";
|
|
5
|
+
export interface ValueLabelsOptions {
|
|
6
|
+
elementAccessors: {
|
|
7
|
+
getBlock: () => Block;
|
|
8
|
+
};
|
|
9
|
+
data: {
|
|
10
|
+
keyFieldName: string;
|
|
11
|
+
};
|
|
12
|
+
canvas: {
|
|
13
|
+
keyAxisOrient: Orient;
|
|
14
|
+
valueLabels: TwoDimensionalValueLabels;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export interface ValueLabelAttrs {
|
|
18
|
+
x: (data: MdtChartsDataRow) => number;
|
|
19
|
+
y: (data: MdtChartsDataRow) => number;
|
|
20
|
+
textAnchor: ValueLabelAnchor;
|
|
21
|
+
dominantBaseline: ValueLabelDominantBaseline;
|
|
22
|
+
}
|
|
23
|
+
export declare class ChartValueLabels {
|
|
24
|
+
private readonly globalOptions;
|
|
25
|
+
private readonly chart;
|
|
26
|
+
private static readonly valueLabelClass;
|
|
27
|
+
constructor(globalOptions: ValueLabelsOptions, chart: TwoDimensionalChartModel);
|
|
28
|
+
render(scales: Scales, data: MdtChartsDataRow[]): void;
|
|
29
|
+
update(scales: Scales, newData: MdtChartsDataRow[]): Promise<void[]>;
|
|
30
|
+
static getChartValueLabelsClassName(): string;
|
|
31
|
+
private getAllValueLabelsOfChart;
|
|
32
|
+
private setAttrs;
|
|
33
|
+
private setClasses;
|
|
34
|
+
}
|
|
35
|
+
export declare class CanvasValueLabels {
|
|
36
|
+
private readonly options;
|
|
37
|
+
private chartsValueLabels;
|
|
38
|
+
constructor(options: ValueLabelsOptions);
|
|
39
|
+
render(scales: ScalesWithSecondary, charts: TwoDimensionalChartModel[], data: MdtChartsDataSource, dataOptions: OptionsModelData): void;
|
|
40
|
+
update(scales: ScalesWithSecondary, charts: TwoDimensionalChartModel[], data: MdtChartsDataSource, dataOptions: OptionsModelData): void;
|
|
41
|
+
private toggleOldValueLabelsVisibility;
|
|
42
|
+
private hideValueLabelsCollision;
|
|
43
|
+
private getAllValueLabels;
|
|
44
|
+
private getChartScales;
|
|
45
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { NamesHelper } from "../../../engine/helpers/namesHelper";
|
|
2
|
+
import { ValueLabelsHelper } from "../../../engine/features/valueLabels/valueLabelsHelper";
|
|
3
|
+
import { Helper } from "../../../engine/helpers/helper";
|
|
4
|
+
import { select } from "d3-selection";
|
|
5
|
+
import { DomHelper } from "../../../engine/helpers/domHelper";
|
|
6
|
+
import { CLASSES } from "../../../model/modelBuilder";
|
|
7
|
+
import { ValueLabelsCollision } from "../../../engine/features/valueLabelsCollision/valueLabelsCollision";
|
|
8
|
+
export class ChartValueLabels {
|
|
9
|
+
constructor(globalOptions, chart) {
|
|
10
|
+
this.globalOptions = globalOptions;
|
|
11
|
+
this.chart = chart;
|
|
12
|
+
}
|
|
13
|
+
render(scales, data) {
|
|
14
|
+
this.chart.data.valueFields.forEach((valueField, vfIndex) => {
|
|
15
|
+
const valueLabels = this.getAllValueLabelsOfChart(vfIndex)
|
|
16
|
+
.data(data)
|
|
17
|
+
.enter()
|
|
18
|
+
.append('text');
|
|
19
|
+
const attrs = ValueLabelsHelper.getValueLabelsAttrs(this.globalOptions, this.chart.valueLabels, scales, valueField);
|
|
20
|
+
this.setAttrs(valueLabels, attrs, valueField.name, this.chart.valueLabels.format);
|
|
21
|
+
this.setClasses(valueLabels, this.chart.cssClasses, vfIndex);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
update(scales, newData) {
|
|
25
|
+
const updatePromises = [];
|
|
26
|
+
this.chart.data.valueFields.forEach((valueField, vfIndex) => {
|
|
27
|
+
const updateProms = new Promise((resolve) => {
|
|
28
|
+
const valueLabels = this.getAllValueLabelsOfChart(vfIndex)
|
|
29
|
+
.data(newData);
|
|
30
|
+
valueLabels.exit().remove();
|
|
31
|
+
const attrs = ValueLabelsHelper.getValueLabelsAttrs(this.globalOptions, this.chart.valueLabels, scales, valueField);
|
|
32
|
+
const newValueLabels = valueLabels
|
|
33
|
+
.enter()
|
|
34
|
+
.append('text');
|
|
35
|
+
const mergedValueLabels = newValueLabels.merge(valueLabels);
|
|
36
|
+
this.setAttrs(newValueLabels, attrs, valueField.name, this.chart.valueLabels.format);
|
|
37
|
+
this.setClasses(mergedValueLabels, this.chart.cssClasses, vfIndex);
|
|
38
|
+
this.setAttrs(valueLabels, attrs, valueField.name, this.chart.valueLabels.format, true, resolve);
|
|
39
|
+
});
|
|
40
|
+
updatePromises.push(updateProms);
|
|
41
|
+
});
|
|
42
|
+
return Promise.all(updatePromises);
|
|
43
|
+
}
|
|
44
|
+
static getChartValueLabelsClassName() {
|
|
45
|
+
return ChartValueLabels.valueLabelClass;
|
|
46
|
+
}
|
|
47
|
+
getAllValueLabelsOfChart(vfIndex) {
|
|
48
|
+
const block = this.globalOptions.elementAccessors.getBlock().svg.getChartBlock();
|
|
49
|
+
return block
|
|
50
|
+
.selectAll(`.${ChartValueLabels.valueLabelClass}.${CLASSES.dataLabel}${Helper.getCssClassesLine(this.chart.cssClasses)}.chart-element-${vfIndex}`);
|
|
51
|
+
}
|
|
52
|
+
setAttrs(valueLabels, attrs, valueFieldName, formatter, animate = false, onEndAnimation) {
|
|
53
|
+
const animationName = 'labels-updating';
|
|
54
|
+
valueLabels
|
|
55
|
+
.text(d => formatter(d[valueFieldName]))
|
|
56
|
+
.attr('dominant-baseline', attrs.dominantBaseline)
|
|
57
|
+
.attr('text-anchor', attrs.textAnchor);
|
|
58
|
+
if (animate) {
|
|
59
|
+
const transition = valueLabels
|
|
60
|
+
.interrupt(animationName)
|
|
61
|
+
.transition(animationName)
|
|
62
|
+
.duration(this.globalOptions.elementAccessors.getBlock().transitionManager.durations.chartUpdate)
|
|
63
|
+
.attr('x', d => attrs.x(d))
|
|
64
|
+
.attr('y', d => attrs.y(d));
|
|
65
|
+
if (onEndAnimation)
|
|
66
|
+
transition.on('end', onEndAnimation);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
valueLabels
|
|
70
|
+
.attr('x', d => attrs.x(d))
|
|
71
|
+
.attr('y', d => attrs.y(d));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
setClasses(textLabels, cssClasses, vfIndex) {
|
|
75
|
+
textLabels.classed(ChartValueLabels.valueLabelClass, true);
|
|
76
|
+
textLabels.classed(CLASSES.dataLabel, true);
|
|
77
|
+
DomHelper.setCssClasses(textLabels, Helper.getCssClassesWithElementIndex(cssClasses, vfIndex));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
ChartValueLabels.valueLabelClass = NamesHelper.getClassName("value-label");
|
|
81
|
+
export class CanvasValueLabels {
|
|
82
|
+
constructor(options) {
|
|
83
|
+
this.options = options;
|
|
84
|
+
this.chartsValueLabels = [];
|
|
85
|
+
}
|
|
86
|
+
render(scales, charts, data, dataOptions) {
|
|
87
|
+
const chartsWithLabels = charts.filter(chart => { var _a; return (_a = chart.valueLabels) === null || _a === void 0 ? void 0 : _a.show; });
|
|
88
|
+
if (chartsWithLabels.length === 0)
|
|
89
|
+
return;
|
|
90
|
+
chartsWithLabels.forEach(chart => {
|
|
91
|
+
const chartScales = this.getChartScales(scales, chart);
|
|
92
|
+
const chartValueLabels = new ChartValueLabels(this.options, chart);
|
|
93
|
+
this.chartsValueLabels.push(chartValueLabels);
|
|
94
|
+
chartValueLabels.render(chartScales, data[dataOptions.dataSource]);
|
|
95
|
+
});
|
|
96
|
+
if (this.options.canvas.valueLabels.collision.mode === 'hide') {
|
|
97
|
+
this.hideValueLabelsCollision();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
update(scales, charts, data, dataOptions) {
|
|
101
|
+
const chartsWithLabels = charts.filter(chart => { var _a; return (_a = chart.valueLabels) === null || _a === void 0 ? void 0 : _a.show; });
|
|
102
|
+
if (chartsWithLabels.length === 0)
|
|
103
|
+
return;
|
|
104
|
+
if (this.options.canvas.valueLabels.collision.mode === 'hide')
|
|
105
|
+
this.toggleOldValueLabelsVisibility();
|
|
106
|
+
const chartsUpdatePromises = chartsWithLabels.map((chart, index) => {
|
|
107
|
+
const chartScales = this.getChartScales(scales, chart);
|
|
108
|
+
return this.chartsValueLabels[index].update(chartScales, data[dataOptions.dataSource]);
|
|
109
|
+
});
|
|
110
|
+
if (this.options.canvas.valueLabels.collision.mode === 'hide') {
|
|
111
|
+
Promise.all(chartsUpdatePromises).then(() => {
|
|
112
|
+
this.hideValueLabelsCollision();
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
toggleOldValueLabelsVisibility() {
|
|
117
|
+
const oldValueLabels = this.getAllValueLabels();
|
|
118
|
+
oldValueLabels.each(function () {
|
|
119
|
+
if (this.style.display === 'none')
|
|
120
|
+
select(this).style('display', 'block');
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
hideValueLabelsCollision() {
|
|
124
|
+
const newValueLabels = this.getAllValueLabels();
|
|
125
|
+
const valueLabelElementsRectInfo = ValueLabelsCollision.getValueLabelElementsRectInfo(newValueLabels);
|
|
126
|
+
ValueLabelsCollision.toggleValueLabelElementsVisibility(valueLabelElementsRectInfo);
|
|
127
|
+
}
|
|
128
|
+
getAllValueLabels() {
|
|
129
|
+
const block = this.options.elementAccessors.getBlock().svg.getChartBlock();
|
|
130
|
+
return block
|
|
131
|
+
.selectAll(`.${ChartValueLabels.getChartValueLabelsClassName()}`);
|
|
132
|
+
}
|
|
133
|
+
getChartScales(scales, chart) {
|
|
134
|
+
return {
|
|
135
|
+
key: scales.key,
|
|
136
|
+
value: chart.data.valueGroup === "secondary" ? scales.valueSecondary : scales.value
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ValueLabelAttrs, ValueLabelsOptions } from "../../../engine/features/valueLabels/valueLabels";
|
|
2
|
+
import { TwoDimChartValueLabelsOptions, ValueField } from "../../../model/model";
|
|
3
|
+
import { Scales } from "../../../engine/features/scale/scale";
|
|
4
|
+
export declare class ValueLabelsHelper {
|
|
5
|
+
static getValueLabelsAttrs(globalOptions: ValueLabelsOptions, valueLabels: TwoDimChartValueLabelsOptions, scales: Scales, valueField: ValueField): ValueLabelAttrs;
|
|
6
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Scale } from "../../../engine/features/scale/scale";
|
|
2
|
+
export class ValueLabelsHelper {
|
|
3
|
+
static getValueLabelsAttrs(globalOptions, valueLabels, scales, valueField) {
|
|
4
|
+
let attrs = {
|
|
5
|
+
x: null,
|
|
6
|
+
y: null,
|
|
7
|
+
dominantBaseline: valueLabels.dominantBaseline,
|
|
8
|
+
textAnchor: valueLabels.textAnchor
|
|
9
|
+
};
|
|
10
|
+
const orient = globalOptions.canvas.keyAxisOrient;
|
|
11
|
+
if (orient === 'left' || orient === 'right') {
|
|
12
|
+
attrs.x = d => valueLabels.handleX(scales.value(d[valueField.name]));
|
|
13
|
+
attrs.y = d => valueLabels.handleY(Scale.getScaledValue(scales.key, d[globalOptions.data.keyFieldName]));
|
|
14
|
+
}
|
|
15
|
+
else if (orient === 'bottom' || orient === 'top') {
|
|
16
|
+
attrs.x = d => valueLabels.handleX(Scale.getScaledValue(scales.key, d[globalOptions.data.keyFieldName]));
|
|
17
|
+
attrs.y = d => valueLabels.handleY(scales.value(d[valueField.name]));
|
|
18
|
+
}
|
|
19
|
+
return attrs;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Selection } from "d3-selection";
|
|
2
|
+
export declare type ValueLabelOnCanvasIndex = number;
|
|
3
|
+
export interface BoundingRect {
|
|
4
|
+
x: number;
|
|
5
|
+
y: number;
|
|
6
|
+
width: number;
|
|
7
|
+
height: number;
|
|
8
|
+
}
|
|
9
|
+
export interface ValueLabelElementRectInfo {
|
|
10
|
+
index: ValueLabelOnCanvasIndex;
|
|
11
|
+
boundingClientRect: BoundingRect;
|
|
12
|
+
}
|
|
13
|
+
export interface ValueLabelElement extends ValueLabelElementRectInfo {
|
|
14
|
+
svgElement: SVGTextElement;
|
|
15
|
+
}
|
|
16
|
+
export interface LabelVisibility {
|
|
17
|
+
index: ValueLabelOnCanvasIndex;
|
|
18
|
+
isVisible: boolean;
|
|
19
|
+
}
|
|
20
|
+
export declare class ValueLabelsCollision {
|
|
21
|
+
static getValueLabelElementsRectInfo(valueLabels: Selection<SVGTextElement, unknown, SVGGElement, unknown>): ValueLabelElement[];
|
|
22
|
+
static toggleValueLabelElementsVisibility(elements: ValueLabelElement[]): void;
|
|
23
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { select } from "d3-selection";
|
|
2
|
+
import { ValueLabelsCollisionHelper } from "../../../engine/features/valueLabelsCollision/valueLabelsCollisionHelper";
|
|
3
|
+
export class ValueLabelsCollision {
|
|
4
|
+
static getValueLabelElementsRectInfo(valueLabels) {
|
|
5
|
+
let ValueLabelElementsReactInfo = [];
|
|
6
|
+
valueLabels.each(function (_, index) {
|
|
7
|
+
const { x, y, height, width } = this.getBoundingClientRect();
|
|
8
|
+
ValueLabelElementsReactInfo.push({
|
|
9
|
+
index,
|
|
10
|
+
svgElement: this,
|
|
11
|
+
boundingClientRect: { x, y, width, height }
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
return ValueLabelElementsReactInfo;
|
|
15
|
+
}
|
|
16
|
+
static toggleValueLabelElementsVisibility(elements) {
|
|
17
|
+
const labelsVisibility = ValueLabelsCollisionHelper.calculateValueLabelsVisibility(elements);
|
|
18
|
+
labelsVisibility.forEach(label => {
|
|
19
|
+
const labelInfo = elements.find(element => element.index === label.index);
|
|
20
|
+
if (labelInfo && !label.isVisible)
|
|
21
|
+
select(labelInfo.svgElement).style('display', 'none');
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { LabelVisibility, ValueLabelElementRectInfo } from "../../../engine/features/valueLabelsCollision/valueLabelsCollision";
|
|
2
|
+
export declare class ValueLabelsCollisionHelper {
|
|
3
|
+
static calculateValueLabelsVisibility(elements: ValueLabelElementRectInfo[]): Map<number, LabelVisibility>;
|
|
4
|
+
private static isOverlapping;
|
|
5
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export class ValueLabelsCollisionHelper {
|
|
2
|
+
static calculateValueLabelsVisibility(elements) {
|
|
3
|
+
const sortedLabels = elements.sort((label1, label2) => label1.boundingClientRect.x - label2.boundingClientRect.x);
|
|
4
|
+
const activeLabels = [];
|
|
5
|
+
const labelsVisibility = new Map();
|
|
6
|
+
elements.forEach(label => {
|
|
7
|
+
labelsVisibility.set(label.index, { index: label.index, isVisible: true });
|
|
8
|
+
});
|
|
9
|
+
sortedLabels.forEach(currentLabel => {
|
|
10
|
+
for (let i = activeLabels.length - 1; i >= 0; i--) {
|
|
11
|
+
const activeLabel = activeLabels[i];
|
|
12
|
+
if (activeLabel.boundingClientRect.x + activeLabel.boundingClientRect.width < currentLabel.boundingClientRect.x) {
|
|
13
|
+
activeLabels.splice(i, 1);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
for (const activeLabel of activeLabels) {
|
|
17
|
+
if (this.isOverlapping(currentLabel.boundingClientRect, activeLabel.boundingClientRect)) {
|
|
18
|
+
if (currentLabel.boundingClientRect.x > activeLabel.boundingClientRect.x) {
|
|
19
|
+
labelsVisibility.get(currentLabel.index).isVisible = false;
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
else if (currentLabel.boundingClientRect.x === activeLabel.boundingClientRect.x) {
|
|
23
|
+
if (currentLabel.boundingClientRect.y > activeLabel.boundingClientRect.y) {
|
|
24
|
+
labelsVisibility.get(currentLabel.index).isVisible = false;
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
else
|
|
28
|
+
labelsVisibility.get(activeLabel.index).isVisible = false;
|
|
29
|
+
}
|
|
30
|
+
else
|
|
31
|
+
labelsVisibility.get(activeLabel.index).isVisible = false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (labelsVisibility.get(currentLabel.index).isVisible) {
|
|
35
|
+
activeLabels.push(currentLabel);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
return labelsVisibility;
|
|
39
|
+
}
|
|
40
|
+
static isOverlapping(rect1, rect2) {
|
|
41
|
+
return !(rect1.x + rect1.width < rect2.x ||
|
|
42
|
+
rect1.x > rect2.x + rect2.width ||
|
|
43
|
+
rect1.y + rect1.height < rect2.y ||
|
|
44
|
+
rect1.y > rect2.y + rect2.height);
|
|
45
|
+
}
|
|
46
|
+
;
|
|
47
|
+
}
|