mdt-charts 1.18.2 → 1.18.4
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 +30 -3
- package/lib/engine/contentManager/contentManagerFactory.js +0 -2
- package/lib/engine/features/axis/axis.d.ts +1 -0
- package/lib/engine/features/axis/axis.js +19 -2
- package/lib/engine/features/axis/axisHelper.js +3 -1
- package/lib/engine/features/legend/legend.d.ts +2 -2
- package/lib/engine/features/legend/legendHelper.d.ts +2 -2
- package/lib/engine/features/legend/legendHelper.js +0 -3
- package/lib/engine/features/scale/scale.d.ts +4 -0
- package/lib/engine/features/scale/scale.js +4 -0
- package/lib/engine/features/title/title.d.ts +1 -1
- package/lib/engine/features/title/title.js +2 -3
- package/lib/engine/features/tolltip/tooltip.d.ts +0 -1
- package/lib/engine/features/tolltip/tooltip.js +2 -21
- package/lib/engine/features/tolltip/tooltipDomHelper.d.ts +6 -3
- package/lib/engine/features/tolltip/tooltipDomHelper.js +64 -27
- package/lib/engine/filterManager/filterEventManager.d.ts +6 -0
- package/lib/engine/filterManager/filterEventManager.js +8 -0
- package/lib/engine/polarNotation/polarManager.js +1 -1
- package/lib/engine/twoDimensionalNotation/line/line.d.ts +6 -0
- package/lib/engine/twoDimensionalNotation/line/line.js +7 -8
- package/lib/engine/twoDimensionalNotation/line/lineHelper.d.ts +4 -1
- package/lib/engine/twoDimensionalNotation/line/lineHelper.js +18 -6
- package/lib/engine/twoDimensionalNotation/twoDimensionalManager.js +11 -9
- package/lib/model/EventEmitter.d.ts +10 -0
- package/lib/model/EventEmitter.js +26 -0
- package/lib/model/dataManagerModel/dataManagerModel.d.ts +0 -1
- package/lib/model/dataManagerModel/dataManagerModel.js +0 -13
- package/lib/model/featuresModel/axisModel.d.ts +1 -0
- package/lib/model/featuresModel/axisModel.js +13 -2
- package/lib/model/featuresModel/scaleModel/scaleDomainService.d.ts +3 -2
- package/lib/model/featuresModel/scaleModel/scaleDomainService.js +16 -6
- package/lib/model/featuresModel/scaleModel/scaleModel.d.ts +1 -0
- package/lib/model/featuresModel/scaleModel/scaleModel.js +12 -0
- package/lib/model/helpers/modelHelper.d.ts +2 -2
- package/lib/model/helpers/modelHelper.js +11 -22
- package/lib/model/margin/twoDim/twoDimMarginModel.d.ts +1 -1
- package/lib/model/margin/twoDim/twoDimMarginModel.js +3 -3
- package/lib/model/model.d.ts +6 -2
- package/lib/model/modelBuilder.js +0 -13
- package/lib/model/modelInstance/configReader.d.ts +2 -0
- package/lib/model/modelInstance/configReader.js +11 -1
- package/lib/model/notations/twoDimensionalModel.js +9 -2
- package/lib/style/charts-main.css +9 -7
- package/lib/style/charts-main.less +9 -7
- package/lib/style/css-vars.css +3 -0
- package/package.json +3 -3
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { Line as ILine } from 'd3-shape';
|
|
2
2
|
import { MdtChartsDataRow } from '../../../config/config';
|
|
3
|
-
import { Orient, BlockMargin, LineCurveType, TwoDimensionalChartModel } from "../../../model/model";
|
|
3
|
+
import { Orient, BlockMargin, LineCurveType, TwoDimensionalChartModel, LineLikeChartRenderOptions } from "../../../model/model";
|
|
4
4
|
import { Scales } from "../../features/scale/scale";
|
|
5
5
|
import { Pipeline } from '../../helpers/pipeline/Pipeline';
|
|
6
6
|
import { BaseType, Selection } from 'd3-selection';
|
|
7
|
+
import { Segment } from './line';
|
|
7
8
|
interface LineGeneratorFactoryOptions {
|
|
8
9
|
keyAxisOrient: Orient;
|
|
9
10
|
scales: Scales;
|
|
10
11
|
keyFieldName: string;
|
|
11
12
|
margin: BlockMargin;
|
|
12
13
|
curve: LineCurveType;
|
|
14
|
+
shouldRenderLine: LineLikeChartRenderOptions;
|
|
13
15
|
}
|
|
14
16
|
export declare class LineGeneratorFactory {
|
|
15
17
|
private options;
|
|
@@ -19,4 +21,5 @@ export declare class LineGeneratorFactory {
|
|
|
19
21
|
}
|
|
20
22
|
export declare function onLineChartInit(creatingPipeline: Pipeline<Selection<SVGElement, any, BaseType, any>, TwoDimensionalChartModel>): void;
|
|
21
23
|
export declare function applyLineDash(lineSelection: Selection<SVGElement, any, BaseType, any>, dashSize: number, gapSize: number): Selection<SVGElement, any, BaseType, any>;
|
|
24
|
+
export declare function getStackedData(data: MdtChartsDataRow[], chart: TwoDimensionalChartModel): Segment[][];
|
|
22
25
|
export {};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { stack } from 'd3-shape';
|
|
1
2
|
import { Scale } from "../../features/scale/scale";
|
|
2
3
|
import { LineGenerator } from './lineGenerator';
|
|
3
4
|
export class LineGeneratorFactory {
|
|
@@ -5,23 +6,23 @@ export class LineGeneratorFactory {
|
|
|
5
6
|
this.options = options;
|
|
6
7
|
}
|
|
7
8
|
getLineGenerator(valueFieldName) {
|
|
8
|
-
const { keyAxisOrient, scales, keyFieldName, margin } = this.options;
|
|
9
|
+
const { keyAxisOrient, scales, keyFieldName, margin, shouldRenderLine } = this.options;
|
|
9
10
|
const generator = new LineGenerator({ curve: this.options.curve });
|
|
10
11
|
if (keyAxisOrient === 'bottom' || keyAxisOrient === 'top') {
|
|
11
|
-
return generator.get(d => Scale.getScaledValue(scales.key, d[keyFieldName]) + margin.left, d => scales.value(d[valueFieldName]) + margin.top);
|
|
12
|
+
return generator.get(d => Scale.getScaledValue(scales.key, d[keyFieldName]) + margin.left, d => scales.value(d[valueFieldName]) + margin.top).defined(d => shouldRenderLine(d, valueFieldName));
|
|
12
13
|
}
|
|
13
14
|
if (keyAxisOrient === 'left' || keyAxisOrient === 'right') {
|
|
14
|
-
return generator.get(d => scales.value(d[valueFieldName]) + margin.left, d => Scale.getScaledValue(scales.key, d[keyFieldName]) + margin.top);
|
|
15
|
+
return generator.get(d => scales.value(d[valueFieldName]) + margin.left, d => Scale.getScaledValue(scales.key, d[keyFieldName]) + margin.top).defined(d => shouldRenderLine(d, valueFieldName));
|
|
15
16
|
}
|
|
16
17
|
}
|
|
17
18
|
getSegmentedLineGenerator() {
|
|
18
|
-
const { keyAxisOrient, scales, keyFieldName, margin } = this.options;
|
|
19
|
+
const { keyAxisOrient, scales, keyFieldName, margin, shouldRenderLine } = this.options;
|
|
19
20
|
const generator = new LineGenerator({ curve: this.options.curve });
|
|
20
21
|
if (keyAxisOrient === 'bottom' || keyAxisOrient === 'top') {
|
|
21
|
-
return generator.get(d => Scale.getScaledValue(scales.key, d.data[keyFieldName]) + margin.left, d => scales.value(d[1]) + margin.top);
|
|
22
|
+
return generator.get(d => Scale.getScaledValue(scales.key, d.data[keyFieldName]) + margin.left, d => scales.value(d[1]) + margin.top).defined(d => shouldRenderLine(d.data, d.fieldName));
|
|
22
23
|
}
|
|
23
24
|
if (keyAxisOrient === 'left' || keyAxisOrient === 'right') {
|
|
24
|
-
return generator.get(d => scales.value(d[1]) + margin.left, d => Scale.getScaledValue(scales.key, d.data[keyFieldName]) + margin.top);
|
|
25
|
+
return generator.get(d => scales.value(d[1]) + margin.left, d => Scale.getScaledValue(scales.key, d.data[keyFieldName]) + margin.top).defined(d => shouldRenderLine(d.data, d.fieldName));
|
|
25
26
|
}
|
|
26
27
|
}
|
|
27
28
|
}
|
|
@@ -36,3 +37,14 @@ export function onLineChartInit(creatingPipeline) {
|
|
|
36
37
|
export function applyLineDash(lineSelection, dashSize, gapSize) {
|
|
37
38
|
return lineSelection.style('stroke-dasharray', `${dashSize} ${gapSize}`);
|
|
38
39
|
}
|
|
40
|
+
export function getStackedData(data, chart) {
|
|
41
|
+
let stackedData = stack().keys(chart.data.valueFields.map(field => field.name))(data)
|
|
42
|
+
.map((layer, index) => {
|
|
43
|
+
const fieldName = chart.data.valueFields[index].name;
|
|
44
|
+
return layer.map((segment) => {
|
|
45
|
+
segment.fieldName = fieldName;
|
|
46
|
+
return segment;
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
return stackedData;
|
|
50
|
+
}
|
|
@@ -16,7 +16,7 @@ import { Line } from "./line/line";
|
|
|
16
16
|
export class TwoDimensionalManager {
|
|
17
17
|
render(engine, model) {
|
|
18
18
|
const options = model.options;
|
|
19
|
-
const scales = Scale.
|
|
19
|
+
const scales = Scale.getScalesWithSecondary(options.scale.key, options.scale.value, options.scale.valueSecondary, options.chartSettings.bar);
|
|
20
20
|
engine.block.scales = scales;
|
|
21
21
|
engine.block.svg.render(model.blockCanvas.size);
|
|
22
22
|
Axis.render(engine.block, scales, options.scale, options.axis, model.blockCanvas.size);
|
|
@@ -42,12 +42,12 @@ export class TwoDimensionalManager {
|
|
|
42
42
|
updateData(block, model, data) {
|
|
43
43
|
block.transitionManager.interruptTransitions();
|
|
44
44
|
block.filterEventManager.updateData(data[model.options.data.dataSource]);
|
|
45
|
-
Title.updateData(model.options.title);
|
|
45
|
+
Title.updateData(block, model.options.title);
|
|
46
46
|
TipBox.clearEvents(block);
|
|
47
47
|
Tooltip.hide(block);
|
|
48
48
|
const options = model.options;
|
|
49
49
|
ElementHighlighter.remove2DChartsFullHighlighting(block, options.charts);
|
|
50
|
-
const scales = Scale.
|
|
50
|
+
const scales = Scale.getScalesWithSecondary(options.scale.key, options.scale.value, options.scale.valueSecondary, options.chartSettings.bar);
|
|
51
51
|
const keyDomainEquality = Helper.checkDomainsEquality(block.scales.key.domain(), scales.key.domain());
|
|
52
52
|
block.scales = scales;
|
|
53
53
|
Axis.update(block, scales, options.scale, options.axis, model.blockCanvas.size, keyDomainEquality);
|
|
@@ -80,12 +80,13 @@ export class TwoDimensionalManager {
|
|
|
80
80
|
block.svg.renderBarHatchPattern();
|
|
81
81
|
block.svg.renderChartsBlock();
|
|
82
82
|
charts.forEach((chart) => {
|
|
83
|
+
const chartScales = { key: scales.key, value: chart.data.valueGroup === "secondary" ? scales.valueSecondary : scales.value };
|
|
83
84
|
if (chart.type === 'bar')
|
|
84
|
-
Bar.get().render(block,
|
|
85
|
+
Bar.get().render(block, chartScales, data[dataOptions.dataSource], dataOptions.keyField, margin, keyAxisOrient, chart, blockSize, chartSettings.bar, BarHelper.getBarsInGroupAmount(charts), chart.isSegmented, charts.findIndex(ch => ch.type === 'bar'));
|
|
85
86
|
else if (chart.type === 'line')
|
|
86
|
-
Line.get({ staticSettings: chartSettings.lineLike }).render(block,
|
|
87
|
+
Line.get({ staticSettings: chartSettings.lineLike }).render(block, chartScales, data[dataOptions.dataSource], dataOptions.keyField, margin, keyAxisOrient, chart);
|
|
87
88
|
else if (chart.type === 'area')
|
|
88
|
-
Area.render(block,
|
|
89
|
+
Area.render(block, chartScales, data[dataOptions.dataSource], dataOptions.keyField, margin, keyAxisOrient, chart, blockSize);
|
|
89
90
|
});
|
|
90
91
|
EmbeddedLabels.raiseGroups(block);
|
|
91
92
|
}
|
|
@@ -93,15 +94,16 @@ export class TwoDimensionalManager {
|
|
|
93
94
|
block.svg.updateChartClipPath(margin, blockSize);
|
|
94
95
|
let promises = [];
|
|
95
96
|
charts.forEach((chart) => {
|
|
97
|
+
const chartScales = { key: scales.key, value: chart.data.valueGroup === "secondary" ? scales.valueSecondary : scales.value };
|
|
96
98
|
let proms;
|
|
97
99
|
if (chart.type === 'bar') {
|
|
98
|
-
proms = Bar.get().update(block, data[dataOptions.dataSource],
|
|
100
|
+
proms = Bar.get().update(block, data[dataOptions.dataSource], chartScales, margin, keyAxisOrient, chart, blockSize, BarHelper.getBarsInGroupAmount(charts), dataOptions.keyField, charts.findIndex(ch => ch.type === 'bar'), chartSettings.bar, chart.isSegmented);
|
|
99
101
|
}
|
|
100
102
|
else if (chart.type === 'line') {
|
|
101
|
-
proms = Line.get({ staticSettings: chartSettings.lineLike }).update(block,
|
|
103
|
+
proms = Line.get({ staticSettings: chartSettings.lineLike }).update(block, chartScales, data[dataOptions.dataSource], dataOptions.keyField, margin, keyAxisOrient, chart);
|
|
102
104
|
}
|
|
103
105
|
else if (chart.type === 'area') {
|
|
104
|
-
proms = Area.update(block,
|
|
106
|
+
proms = Area.update(block, chartScales, data[dataOptions.dataSource], dataOptions.keyField, margin, chart, keyAxisOrient, blockSize);
|
|
105
107
|
}
|
|
106
108
|
promises.push(...proms);
|
|
107
109
|
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare class EventEmitter<E = Record<string, Record<string, any>>> {
|
|
2
|
+
private events;
|
|
3
|
+
subscribe<T extends keyof E>(code: T, listener: (args: E[T]) => void): () => void;
|
|
4
|
+
unsubscribe<T extends keyof E>(code: T, listener: (args: E[T]) => void): void;
|
|
5
|
+
emit<T extends keyof E>(code: T, args?: E[T]): void;
|
|
6
|
+
getSubscribeController(): {
|
|
7
|
+
subscribe: <T extends keyof E>(code: T, listener: (args: E[T]) => void) => () => void;
|
|
8
|
+
unsubscribe: <T_1 extends keyof E>(code: T_1, listener: (args: E[T_1]) => void) => void;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export class EventEmitter {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.events = {};
|
|
4
|
+
}
|
|
5
|
+
subscribe(code, listener) {
|
|
6
|
+
if (!this.events[code])
|
|
7
|
+
this.events[code] = [];
|
|
8
|
+
this.events[code].push(listener);
|
|
9
|
+
return () => this.unsubscribe(code, listener);
|
|
10
|
+
}
|
|
11
|
+
unsubscribe(code, listener) {
|
|
12
|
+
var _a;
|
|
13
|
+
this.events[code] = (_a = this.events[code]) === null || _a === void 0 ? void 0 : _a.filter((cur) => cur != listener);
|
|
14
|
+
}
|
|
15
|
+
emit(code, args) {
|
|
16
|
+
(this.events[code] || []).forEach((callback) => {
|
|
17
|
+
callback(args);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
getSubscribeController() {
|
|
21
|
+
return {
|
|
22
|
+
subscribe: (code, listener) => this.subscribe(code, listener),
|
|
23
|
+
unsubscribe: (code, listener) => this.unsubscribe(code, listener)
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -30,7 +30,6 @@ export declare class DataManagerModel {
|
|
|
30
30
|
private static getBarChartsInGroupAmount;
|
|
31
31
|
private static getScopedData;
|
|
32
32
|
private static getScopedChartData;
|
|
33
|
-
private static setDataType;
|
|
34
33
|
private static getTypedData;
|
|
35
34
|
private static getDataLimitByItemSize;
|
|
36
35
|
}
|
|
@@ -8,7 +8,6 @@ import { styledElementValues } from "../modelBuilder";
|
|
|
8
8
|
export class DataManagerModel {
|
|
9
9
|
static getPreparedData(data, allowableKeys, config) {
|
|
10
10
|
const scopedData = this.getScopedData(data, allowableKeys, config.options.data);
|
|
11
|
-
this.setDataType(scopedData, config);
|
|
12
11
|
return scopedData;
|
|
13
12
|
}
|
|
14
13
|
static initDataScope(config, data, designerConfig, legendBlock, modelInstance) {
|
|
@@ -28,7 +27,6 @@ export class DataManagerModel {
|
|
|
28
27
|
return data[dataSourceName].map(dataRow => dataRow[keyFieldName]);
|
|
29
28
|
}
|
|
30
29
|
static initDataScopeFor2D(configOptions, modelInstance, data, designerConfig) {
|
|
31
|
-
// Для interval всегда один элемент, так как там может быть только один столбик
|
|
32
30
|
modelInstance.dataModel.initMaxRecordsAmount(configOptions.data.maxRecordsAmount);
|
|
33
31
|
let itemsLength = 1;
|
|
34
32
|
itemsLength = (configOptions.charts)
|
|
@@ -125,17 +123,6 @@ export class DataManagerModel {
|
|
|
125
123
|
static getScopedChartData(data, allowableKeys, keyFieldName) {
|
|
126
124
|
return data.filter(d => allowableKeys.findIndex(key => key === d[keyFieldName]) !== -1);
|
|
127
125
|
}
|
|
128
|
-
static setDataType(data, config) {
|
|
129
|
-
if (config.options.type === 'interval') {
|
|
130
|
-
const chart = config.options.chart;
|
|
131
|
-
if (chart.data.valueField1.format === 'date') {
|
|
132
|
-
data[config.options.data.dataSource] = this.getTypedData(data[config.options.data.dataSource], chart.data.valueField1);
|
|
133
|
-
}
|
|
134
|
-
if (chart.data.valueField2.format === 'date') {
|
|
135
|
-
data[config.options.data.dataSource] = this.getTypedData(data[config.options.data.dataSource], chart.data.valueField2);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
126
|
static getTypedData(data, field) {
|
|
140
127
|
if (field.format === 'date')
|
|
141
128
|
data.forEach(d => {
|
|
@@ -20,5 +20,6 @@ export declare class AxisModel {
|
|
|
20
20
|
static getKeyAxisLabelPosition(canvasModel: CanvasModel, scopedDataLength: number, axisConfig?: DiscreteAxisOptions): AxisLabelPosition;
|
|
21
21
|
static getLabelSize(labelMaxWidth: number, labelTexts: string[]): LabelSize;
|
|
22
22
|
static getLabelSizeLegacy(labelMaxWidth: number, labelTexts: string[]): LabelSize;
|
|
23
|
+
static getRoundValue(value: number): number;
|
|
23
24
|
private static getKeyAxisTranslateModel;
|
|
24
25
|
}
|
|
@@ -92,7 +92,7 @@ export class AxisModel {
|
|
|
92
92
|
static getLabelSize(labelMaxWidth, labelTexts) {
|
|
93
93
|
const LABEL_ELEMENT_HEIGHT_PX = 17;
|
|
94
94
|
const ONE_UPPER_SYMBOL_WIDTH_PX = 8;
|
|
95
|
-
const longestLabelLength = Math.max(...labelTexts.map(t => ModelHelper.getStringScore(t)));
|
|
95
|
+
const longestLabelLength = labelTexts.length ? Math.max(...labelTexts.map(t => ModelHelper.getStringScore(t))) : 0;
|
|
96
96
|
const longestLabelWidth = ONE_UPPER_SYMBOL_WIDTH_PX * longestLabelLength;
|
|
97
97
|
return {
|
|
98
98
|
height: LABEL_ELEMENT_HEIGHT_PX,
|
|
@@ -118,7 +118,7 @@ export class AxisModel {
|
|
|
118
118
|
biggestScore = ModelHelper.getStringScore(text);
|
|
119
119
|
}
|
|
120
120
|
});
|
|
121
|
-
textBlock.textContent = maxLabel === '0000' ? maxLabel : maxLabel
|
|
121
|
+
textBlock.textContent = maxLabel === '0000' ? maxLabel : maxLabel;
|
|
122
122
|
document.body.append(textBlock);
|
|
123
123
|
maxWidth = Math.ceil(textBlock.getBoundingClientRect().width);
|
|
124
124
|
labelSize.height = textBlock.getBoundingClientRect().height;
|
|
@@ -126,6 +126,17 @@ export class AxisModel {
|
|
|
126
126
|
textBlock.remove();
|
|
127
127
|
return labelSize;
|
|
128
128
|
}
|
|
129
|
+
static getRoundValue(value) {
|
|
130
|
+
const absValue = Math.abs(value);
|
|
131
|
+
const sign = Math.sign(value);
|
|
132
|
+
if (absValue < 10)
|
|
133
|
+
return value;
|
|
134
|
+
const valueStr = absValue.toString();
|
|
135
|
+
const firstTwoDigits = Math.floor(absValue / Math.pow(10, valueStr.length - 2));
|
|
136
|
+
const roundedFirstTwoDigits = firstTwoDigits < 10 ? firstTwoDigits : Math.floor(firstTwoDigits / 5) * 5;
|
|
137
|
+
const roundedNumber = roundedFirstTwoDigits * Math.pow(10, valueStr.length - 2);
|
|
138
|
+
return sign * roundedNumber;
|
|
139
|
+
}
|
|
129
140
|
static getKeyAxisTranslateModel(chartOrientation, axisPosition, canvasModel, getZeroCoordinate) {
|
|
130
141
|
let translateY;
|
|
131
142
|
let translateX;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { MdtChartsDataRow, MdtChartsTwoDimensionalChart, MdtChartsTwoDimensionalOptions,
|
|
2
|
-
export declare function
|
|
1
|
+
import { AxisNumberDomain, MdtChartsDataRow, MdtChartsTwoDimensionalChart, MdtChartsTwoDimensionalOptions, TwoDimensionalValueGroup } from "../../../config/config";
|
|
2
|
+
export declare function getResolvedDomain(domain: AxisNumberDomain, dataRows: MdtChartsDataRow[]): import("../../../config/config").NumberDomain;
|
|
3
|
+
export declare function getScaleLinearDomain(configDomain: AxisNumberDomain, dataRows: MdtChartsDataRow[], configOptions: MdtChartsTwoDimensionalOptions, valueGroup?: TwoDimensionalValueGroup): number[];
|
|
3
4
|
export declare class ScaleDomainCalculator {
|
|
4
5
|
getScaleMinValue(charts: MdtChartsTwoDimensionalChart[], dataRows: MdtChartsDataRow[]): number;
|
|
5
6
|
getScaleMaxValue(charts: MdtChartsTwoDimensionalChart[], dataRows: MdtChartsDataRow[]): number;
|
|
@@ -1,15 +1,25 @@
|
|
|
1
|
-
export function
|
|
1
|
+
export function getResolvedDomain(domain, dataRows) {
|
|
2
|
+
return typeof domain === 'function'
|
|
3
|
+
? domain({ data: dataRows })
|
|
4
|
+
: domain;
|
|
5
|
+
}
|
|
6
|
+
export function getScaleLinearDomain(configDomain, dataRows, configOptions, valueGroup = 'main') {
|
|
2
7
|
const calculator = new ScaleDomainCalculator();
|
|
3
8
|
let domainPeekMin;
|
|
4
9
|
let domainPeekMax;
|
|
5
|
-
|
|
10
|
+
const resolvedConfigDomain = getResolvedDomain(configDomain, dataRows);
|
|
11
|
+
const charts = configOptions.charts.filter(chart => {
|
|
12
|
+
var _a;
|
|
13
|
+
return ((_a = chart.data.valueGroup) !== null && _a !== void 0 ? _a : "main") === valueGroup;
|
|
14
|
+
});
|
|
15
|
+
if (resolvedConfigDomain.start === -1)
|
|
6
16
|
domainPeekMin = calculator.getScaleMinValue(configOptions.charts, dataRows);
|
|
7
17
|
else
|
|
8
|
-
domainPeekMin =
|
|
9
|
-
if (
|
|
10
|
-
domainPeekMax = calculator.getScaleMaxValue(
|
|
18
|
+
domainPeekMin = resolvedConfigDomain.start;
|
|
19
|
+
if (resolvedConfigDomain.end === -1)
|
|
20
|
+
domainPeekMax = calculator.getScaleMaxValue(charts, dataRows);
|
|
11
21
|
else
|
|
12
|
-
domainPeekMax =
|
|
22
|
+
domainPeekMax = resolvedConfigDomain.end;
|
|
13
23
|
if (configOptions.axis.key.position === 'start')
|
|
14
24
|
return [domainPeekMin, domainPeekMax];
|
|
15
25
|
return [domainPeekMax, domainPeekMin];
|
|
@@ -9,5 +9,6 @@ export declare enum ScaleType {
|
|
|
9
9
|
export declare class ScaleModel {
|
|
10
10
|
getScaleKey(allowableKeys: string[], orient: ChartOrientation, canvasModel: CanvasModel, charts: MdtChartsTwoDimensionalChart[], barCharts: MdtChartsTwoDimensionalChart[]): ScaleKeyModel;
|
|
11
11
|
getScaleLinear(options: MdtChartsTwoDimensionalOptions, dataRows: MdtChartsDataRow[], canvasModel: CanvasModel, configReader?: TwoDimConfigReader): ScaleValueModel;
|
|
12
|
+
getScaleSecondaryLinear(options: MdtChartsTwoDimensionalOptions, dataRows: MdtChartsDataRow[], canvasModel: CanvasModel, configReader?: TwoDimConfigReader): ScaleValueModel;
|
|
12
13
|
private getScaleKeyType;
|
|
13
14
|
}
|
|
@@ -29,6 +29,18 @@ export class ScaleModel {
|
|
|
29
29
|
formatter: (_a = configReader === null || configReader === void 0 ? void 0 : configReader.getAxisLabelFormatter()) !== null && _a !== void 0 ? _a : null
|
|
30
30
|
};
|
|
31
31
|
}
|
|
32
|
+
getScaleSecondaryLinear(options, dataRows, canvasModel, configReader) {
|
|
33
|
+
var _a;
|
|
34
|
+
return {
|
|
35
|
+
domain: getScaleLinearDomain(options.axis.value.domain, dataRows, options, 'secondary'),
|
|
36
|
+
range: {
|
|
37
|
+
start: 0,
|
|
38
|
+
end: getScaleValueRangePeek(options.orientation, canvasModel)
|
|
39
|
+
},
|
|
40
|
+
type: "linear",
|
|
41
|
+
formatter: (_a = configReader === null || configReader === void 0 ? void 0 : configReader.getAxisLabelFormatter()) !== null && _a !== void 0 ? _a : null
|
|
42
|
+
};
|
|
43
|
+
}
|
|
32
44
|
getScaleKeyType(charts) {
|
|
33
45
|
if (charts.findIndex((chart) => chart.type === 'bar') === -1)
|
|
34
46
|
return 'point';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { MdtChartsDataSource, IntervalChart } from "../../config/config";
|
|
2
1
|
export declare class ModelHelper {
|
|
2
|
+
private static baseFontSize;
|
|
3
|
+
private static getBaseFontSize;
|
|
3
4
|
static getSum(items: number[]): number;
|
|
4
|
-
static getMinAndMaxOfIntervalData(data: MdtChartsDataSource, dataSource: string, chart: IntervalChart): [Date, Date];
|
|
5
5
|
static getUniqueValues(values: string[]): string[];
|
|
6
6
|
static getStringScore(word: string): number;
|
|
7
7
|
}
|
|
@@ -1,25 +1,13 @@
|
|
|
1
|
+
import { DomHelper } from "../../engine/helpers/domHelper";
|
|
1
2
|
export class ModelHelper {
|
|
3
|
+
static getBaseFontSize() {
|
|
4
|
+
if (!this.baseFontSize)
|
|
5
|
+
this.baseFontSize = parseInt(DomHelper.getCssPropertyValue(document.documentElement, '--chart-base-font-size'));
|
|
6
|
+
return this.baseFontSize;
|
|
7
|
+
}
|
|
2
8
|
static getSum(items) {
|
|
3
9
|
return items.reduce((acc, item) => acc + item, 0);
|
|
4
10
|
}
|
|
5
|
-
static getMinAndMaxOfIntervalData(data, dataSource, chart) {
|
|
6
|
-
let min = data[dataSource][0][chart.data.valueField1.name];
|
|
7
|
-
let max = data[dataSource][0][chart.data.valueField1.name];
|
|
8
|
-
const chartData = data[dataSource];
|
|
9
|
-
const valueField1 = chart.data.valueField1.name;
|
|
10
|
-
const valueField2 = chart.data.valueField2.name;
|
|
11
|
-
chartData.forEach(dataRow => {
|
|
12
|
-
if (dataRow[valueField1] > max)
|
|
13
|
-
max = dataRow[valueField1];
|
|
14
|
-
if (dataRow[valueField1] < min)
|
|
15
|
-
min = dataRow[valueField1];
|
|
16
|
-
if (dataRow[valueField2] > max)
|
|
17
|
-
max = dataRow[valueField2];
|
|
18
|
-
if (dataRow[valueField2] < min)
|
|
19
|
-
min = dataRow[valueField2];
|
|
20
|
-
});
|
|
21
|
-
return [min, max];
|
|
22
|
-
}
|
|
23
11
|
static getUniqueValues(values) {
|
|
24
12
|
const uniqueValues = values.filter((keyValue, index, self) => self.indexOf(keyValue) === index);
|
|
25
13
|
return uniqueValues;
|
|
@@ -27,11 +15,12 @@ export class ModelHelper {
|
|
|
27
15
|
static getStringScore(word) {
|
|
28
16
|
// lower case letter width ~ 0.8 from upper case width.
|
|
29
17
|
// Number width == lower case letter width
|
|
18
|
+
const fontSize = this.getBaseFontSize();
|
|
30
19
|
let score = 0;
|
|
31
|
-
const upperLetterScore =
|
|
32
|
-
const lowerLetterScore =
|
|
33
|
-
const digitScore =
|
|
34
|
-
const otherSymbolScore =
|
|
20
|
+
const upperLetterScore = fontSize / 13;
|
|
21
|
+
const lowerLetterScore = fontSize / 15;
|
|
22
|
+
const digitScore = fontSize / 15;
|
|
23
|
+
const otherSymbolScore = fontSize / 23;
|
|
35
24
|
const specialSmallSymbols = [",", ".", " "];
|
|
36
25
|
for (let i = 0; i < word.length; i++) {
|
|
37
26
|
if (parseFloat(word[i]).toString() !== word[i] && !specialSmallSymbols.includes(word[i]) && word[i].trim().length > 0) {
|
|
@@ -11,7 +11,7 @@ export declare class TwoDimMarginModel {
|
|
|
11
11
|
constructor(designerConfig: DesignerConfig, configReader: TwoDimConfigReader);
|
|
12
12
|
recalcMargin(otherComponents: OtherCommonComponents, modelInstance: ModelInstance): void;
|
|
13
13
|
recalcMarginByVerticalAxisLabel(modelInstance: ModelInstance): void;
|
|
14
|
-
private
|
|
14
|
+
private getMaxLabelSize;
|
|
15
15
|
private recalcVerticalMarginByAxisLabelHeight;
|
|
16
16
|
private recalcHorizontalMarginByAxisLabelWidth;
|
|
17
17
|
}
|
|
@@ -14,7 +14,7 @@ export class TwoDimMarginModel {
|
|
|
14
14
|
recalcMargin(otherComponents, modelInstance) {
|
|
15
15
|
const canvasModel = modelInstance.canvasModel;
|
|
16
16
|
this.twoDimLegendModel.recalcMarginWith2DLegend(modelInstance, otherComponents.legendBlock, this.configReader.options.legend);
|
|
17
|
-
const labelSize = this.
|
|
17
|
+
const labelSize = this.getMaxLabelSize(modelInstance);
|
|
18
18
|
this.recalcVerticalMarginByAxisLabelHeight(labelSize, canvasModel);
|
|
19
19
|
// Если встроенный лейбл показывает ключи, то лейблы оси ключей не показываются
|
|
20
20
|
// При этом все графики должны иметь: embeddedLabels = 'key'
|
|
@@ -36,14 +36,14 @@ export class TwoDimMarginModel {
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
-
|
|
39
|
+
getMaxLabelSize(modelInstance) {
|
|
40
40
|
const keyAxisOrient = AxisModel.getAxisOrient(AxisType.Key, this.configReader.options.orientation, this.configReader.options.axis.key.position);
|
|
41
41
|
let labelsTexts;
|
|
42
42
|
if (keyAxisOrient === 'left' || keyAxisOrient === 'right') {
|
|
43
43
|
labelsTexts = modelInstance.dataModel.repository.getValuesByKeyField();
|
|
44
44
|
}
|
|
45
45
|
else {
|
|
46
|
-
labelsTexts = modelInstance.dataModel.repository
|
|
46
|
+
labelsTexts = this.configReader.calculateBiggestValueAndDecremented(modelInstance.dataModel.repository)
|
|
47
47
|
.map(v => this.configReader.getAxisLabelFormatter()(v).toString());
|
|
48
48
|
}
|
|
49
49
|
return AxisModel.getLabelSize(this.designerConfig.canvas.axisLabel.maxSize.main, labelsTexts);
|
package/lib/model/model.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ChartOrientation, MdtChartsColorField, IntervalChartType, PolarChartType, Size, TooltipOptions, TwoDimensionalChartType, AxisLabelPosition, ShowTickFn } from "../config/config";
|
|
1
|
+
import { ChartOrientation, MdtChartsColorField, IntervalChartType, PolarChartType, Size, TooltipOptions, TwoDimensionalChartType, AxisLabelPosition, ShowTickFn, MdtChartsDataRow, TwoDimensionalValueGroup } from "../config/config";
|
|
2
2
|
import { DataType, DonutOptionsCanvas, Formatter, StaticLegendBlockCanvas, TooltipSettings, Transitions } from "../designer/designerConfig";
|
|
3
3
|
declare type AxisType = "key" | "value";
|
|
4
4
|
export declare type Orient = "top" | "bottom" | "left" | "right";
|
|
@@ -80,6 +80,7 @@ export interface Field {
|
|
|
80
80
|
export interface IScaleModel {
|
|
81
81
|
key: ScaleKeyModel;
|
|
82
82
|
value: ScaleValueModel;
|
|
83
|
+
valueSecondary?: ScaleValueModel;
|
|
83
84
|
}
|
|
84
85
|
export interface ScaleKeyModel {
|
|
85
86
|
domain: any[];
|
|
@@ -209,7 +210,7 @@ export declare type LegendMarkerShape = "default" | "bar" | "line";
|
|
|
209
210
|
export interface TwoDimensionalChartLegendBarModel extends TwoDimensionalBarLikeChartViewModel {
|
|
210
211
|
width: number;
|
|
211
212
|
}
|
|
212
|
-
export interface TwoDimensionalChartLegendLineModel extends TwoDimensionalLineLikeChartViewModel {
|
|
213
|
+
export interface TwoDimensionalChartLegendLineModel extends Omit<TwoDimensionalLineLikeChartViewModel, 'renderForKey'> {
|
|
213
214
|
width: number;
|
|
214
215
|
}
|
|
215
216
|
interface TwoDimensionalLineLikeChartModel {
|
|
@@ -218,7 +219,9 @@ interface TwoDimensionalLineLikeChartModel {
|
|
|
218
219
|
}
|
|
219
220
|
interface TwoDimensionalLineLikeChartViewModel {
|
|
220
221
|
dashedStyles: LineLikeChartDashOptions;
|
|
222
|
+
renderForKey: LineLikeChartRenderOptions;
|
|
221
223
|
}
|
|
224
|
+
export declare type LineLikeChartRenderOptions = (dataRow: MdtChartsDataRow, valueFieldName: string) => boolean;
|
|
222
225
|
interface TwoDimensionalBarLikeChartModel {
|
|
223
226
|
barViewOptions: TwoDimensionalBarLikeChartViewModel;
|
|
224
227
|
}
|
|
@@ -244,6 +247,7 @@ export interface PolarChartModel extends ChartModel {
|
|
|
244
247
|
}
|
|
245
248
|
export interface TwoDimensionalChartDataModel {
|
|
246
249
|
valueFields: ValueField[];
|
|
250
|
+
valueGroup?: TwoDimensionalValueGroup;
|
|
247
251
|
}
|
|
248
252
|
export interface ValueField extends Field {
|
|
249
253
|
title: string;
|
|
@@ -76,7 +76,6 @@ export function assembleModel(config, data, designerConfig) {
|
|
|
76
76
|
options: null,
|
|
77
77
|
dataSettings: null
|
|
78
78
|
};
|
|
79
|
-
resetFalsyValues(data);
|
|
80
79
|
const dataRows = modelInstance.dataModel.repository.getRawRows();
|
|
81
80
|
const resolvedTitle = getResolvedTitle(config.options.title, dataRows);
|
|
82
81
|
const otherComponents = OtherComponentsModel.getOtherComponentsModel({
|
|
@@ -104,19 +103,7 @@ export function assembleModel(config, data, designerConfig) {
|
|
|
104
103
|
transitions
|
|
105
104
|
};
|
|
106
105
|
}
|
|
107
|
-
function resetFalsyValues(data) {
|
|
108
|
-
for (let setName in data) {
|
|
109
|
-
data[setName].forEach(dataRow => {
|
|
110
|
-
for (let fieldName in dataRow) {
|
|
111
|
-
if (dataRow[fieldName] == null) {
|
|
112
|
-
dataRow[fieldName] = 0;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
106
|
export function getPreparedData(model, data, config) {
|
|
119
|
-
resetFalsyValues(data);
|
|
120
107
|
const isModelOrDataEmpty = !model || Object.keys(model).length === 0 || !data || Object.keys(data).length === 0;
|
|
121
108
|
if (isModelOrDataEmpty)
|
|
122
109
|
return null;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AxisLabelFormatter, MdtChartsConfig, MdtChartsField, MdtChartsFieldName, MdtChartsTwoDimensionalOptions, TwoDimensionalChartType } from "../../config/config";
|
|
2
2
|
import { DesignerConfig } from "../../designer/designerConfig";
|
|
3
|
+
import { DataRepositoryModel } from "../../model/modelInstance/dataModel/dataRepository";
|
|
3
4
|
interface BaseConfigReader {
|
|
4
5
|
getValueFields(): MdtChartsField[];
|
|
5
6
|
}
|
|
@@ -9,6 +10,7 @@ export declare class TwoDimConfigReader implements BaseConfigReader {
|
|
|
9
10
|
readonly options: MdtChartsTwoDimensionalOptions;
|
|
10
11
|
constructor(config: MdtChartsConfig, designerConfig: DesignerConfig);
|
|
11
12
|
getValueFields(): MdtChartsField[];
|
|
13
|
+
calculateBiggestValueAndDecremented(repository: DataRepositoryModel): number[];
|
|
12
14
|
getFieldsBySegments(): MdtChartsFieldName[][];
|
|
13
15
|
getAxisLabelFormatter(): AxisLabelFormatter;
|
|
14
16
|
getLegendItemInfo(): {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getResolvedDomain } from "../../model/featuresModel/scaleModel/scaleDomainService";
|
|
1
2
|
export function getConfigReader(config, designerConfig) {
|
|
2
3
|
if (config.options.type === "2d")
|
|
3
4
|
return new TwoDimConfigReader(config, designerConfig);
|
|
@@ -17,9 +18,18 @@ export class TwoDimConfigReader {
|
|
|
17
18
|
});
|
|
18
19
|
return fields;
|
|
19
20
|
}
|
|
21
|
+
calculateBiggestValueAndDecremented(repository) {
|
|
22
|
+
const domain = this.options.axis.value.domain;
|
|
23
|
+
const resolvedDomain = getResolvedDomain(domain, repository.getRawRows());
|
|
24
|
+
if (resolvedDomain && resolvedDomain.end !== -1) {
|
|
25
|
+
return [resolvedDomain.end, resolvedDomain.end - 1];
|
|
26
|
+
}
|
|
27
|
+
return repository.getBiggestValueAndDecremented(this.getFieldsBySegments());
|
|
28
|
+
}
|
|
20
29
|
getFieldsBySegments() {
|
|
21
30
|
const segments = [];
|
|
22
|
-
this.options.charts.
|
|
31
|
+
const mainCharts = this.options.charts.filter(chart => chart.data.valueGroup !== 'secondary');
|
|
32
|
+
mainCharts.forEach(chart => {
|
|
23
33
|
if (!chart.isSegmented)
|
|
24
34
|
segments.push(...chart.data.valueFields.map(vf => [vf.name]));
|
|
25
35
|
else
|
|
@@ -14,6 +14,9 @@ export class TwoDimensionalModel {
|
|
|
14
14
|
const scaleMarginRecalcer = new ScaleAxisRecalcer(() => scaleModel.getScaleLinear(options, modelInstance.dataModel.repository.getScopedRows(), canvasModel, configReader));
|
|
15
15
|
scaleMarginRecalcer.recalculateMargin(canvasModel, options.orientation, options.axis.key);
|
|
16
16
|
const scaleValueInfo = scaleMarginRecalcer.getScaleValue();
|
|
17
|
+
const secondaryScaleMarginRecalcer = new ScaleAxisRecalcer(() => scaleModel.getScaleSecondaryLinear(options, modelInstance.dataModel.repository.getScopedRows(), canvasModel, configReader));
|
|
18
|
+
secondaryScaleMarginRecalcer.recalculateMargin(canvasModel, options.orientation, options.axis.key);
|
|
19
|
+
const secondaryScaleValueInfo = secondaryScaleMarginRecalcer.getScaleValue();
|
|
17
20
|
return {
|
|
18
21
|
legend: canvasModel.legendCanvas.getModel(),
|
|
19
22
|
title: resolvedTitle,
|
|
@@ -21,7 +24,8 @@ export class TwoDimensionalModel {
|
|
|
21
24
|
orient: options.orientation,
|
|
22
25
|
scale: {
|
|
23
26
|
key: scaleModel.getScaleKey(modelInstance.dataModel.getAllowableKeys(), options.orientation, canvasModel, options.charts, this.getChartsByType(options.charts, 'bar')),
|
|
24
|
-
value: scaleValueInfo.scale
|
|
27
|
+
value: scaleValueInfo.scale,
|
|
28
|
+
valueSecondary: secondaryScaleValueInfo.scale,
|
|
25
29
|
},
|
|
26
30
|
axis: {
|
|
27
31
|
key: AxisModel.getKeyAxis(options, modelInstance.dataModel.repository.getScopedFullSource(), designerConfig.canvas.axisLabel, canvasModel, designerConfig.elementsOptions.tooltip, () => scaleValueInfo.scaleFn(0)),
|
|
@@ -85,7 +89,10 @@ export class TwoDimensionalModel {
|
|
|
85
89
|
}
|
|
86
90
|
}
|
|
87
91
|
},
|
|
88
|
-
lineViewOptions: {
|
|
92
|
+
lineViewOptions: {
|
|
93
|
+
dashedStyles: parseDashStyles((_k = chart.lineStyles) === null || _k === void 0 ? void 0 : _k.dash),
|
|
94
|
+
renderForKey: (dataRow, valueFieldName) => dataRow[valueFieldName] !== null && dataRow[valueFieldName] !== undefined
|
|
95
|
+
},
|
|
89
96
|
barViewOptions: { hatch: { on: (_o = (_m = (_l = chart.barStyles) === null || _l === void 0 ? void 0 : _l.hatch) === null || _m === void 0 ? void 0 : _m.on) !== null && _o !== void 0 ? _o : false } },
|
|
90
97
|
legend: getLegendMarkerOptions(chart),
|
|
91
98
|
index
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
@import './css-vars.css';
|
|
2
|
+
|
|
1
3
|
.wrapper {
|
|
2
4
|
margin: 0 auto;
|
|
3
5
|
position: relative;
|
|
@@ -18,8 +20,8 @@
|
|
|
18
20
|
.data-label {
|
|
19
21
|
font-family: "Roboto";
|
|
20
22
|
font-style: normal;
|
|
21
|
-
font-weight:
|
|
22
|
-
font-size:
|
|
23
|
+
font-weight: 400;
|
|
24
|
+
font-size: var(--chart-base-font-size);
|
|
23
25
|
line-height: 140.62%;
|
|
24
26
|
color: #444444;
|
|
25
27
|
cursor: default;
|
|
@@ -85,9 +87,9 @@
|
|
|
85
87
|
}
|
|
86
88
|
|
|
87
89
|
.legend-label {
|
|
88
|
-
font-size:
|
|
90
|
+
font-size: var(--chart-base-font-size);
|
|
89
91
|
font-family: "Roboto", sans-serif;
|
|
90
|
-
font-weight:
|
|
92
|
+
font-weight: 400;
|
|
91
93
|
color: #444444;
|
|
92
94
|
width: calc(100% - 19px);
|
|
93
95
|
overflow: hidden;
|
|
@@ -130,7 +132,7 @@
|
|
|
130
132
|
z-index: 102;
|
|
131
133
|
max-width: 500px;
|
|
132
134
|
background: rgba(0, 0, 0, 0.82);
|
|
133
|
-
font-size:
|
|
135
|
+
font-size: var(--chart-base-font-size);
|
|
134
136
|
}
|
|
135
137
|
.mdt-charts-tooltip-arrow {
|
|
136
138
|
width: 0;
|
|
@@ -169,7 +171,7 @@
|
|
|
169
171
|
stroke-linecap: round;
|
|
170
172
|
}
|
|
171
173
|
.mdt-charts-tooltip-content .tooltip-head {
|
|
172
|
-
font-size:
|
|
174
|
+
font-size: var(--chart-base-font-size);
|
|
173
175
|
margin-bottom: 10px;
|
|
174
176
|
}
|
|
175
177
|
.mdt-charts-tooltip-content .tooltip-texts {
|
|
@@ -250,7 +252,7 @@
|
|
|
250
252
|
font-family: "Roboto", sans-serif;
|
|
251
253
|
font-style: normal;
|
|
252
254
|
font-weight: 500;
|
|
253
|
-
font-size:
|
|
255
|
+
font-size: var(--chart-base-font-size);
|
|
254
256
|
line-height: 140.62%;
|
|
255
257
|
}
|
|
256
258
|
|