mdt-charts 1.11.1 → 1.12.0

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.
Files changed (32) hide show
  1. package/lib/config/config.d.ts +1 -0
  2. package/lib/engine/features/recordOverflowAlert/recordOverflowAlertCore.d.ts +28 -0
  3. package/lib/engine/features/recordOverflowAlert/recordOverflowAlertCore.js +50 -0
  4. package/lib/engine/intervalNotation/intervalManager.js +0 -3
  5. package/lib/engine/polarNotation/extenders/polarRecordOverflowAlert.d.ts +16 -0
  6. package/lib/engine/polarNotation/extenders/polarRecordOverflowAlert.js +48 -0
  7. package/lib/engine/polarNotation/polarManager.js +10 -5
  8. package/lib/engine/twoDimensionalNotation/extenders/twoDimRecordOverflowAlert.d.ts +15 -0
  9. package/lib/engine/twoDimensionalNotation/extenders/twoDimRecordOverflowAlert.js +32 -0
  10. package/lib/engine/twoDimensionalNotation/twoDimensionalManager.js +9 -3
  11. package/lib/model/dataManagerModel/dataManagerModel.d.ts +26 -0
  12. package/lib/model/dataManagerModel/dataManagerModel.js +132 -0
  13. package/lib/model/dataManagerModel/dataManagerModelService.d.ts +5 -0
  14. package/lib/model/dataManagerModel/dataManagerModelService.js +28 -0
  15. package/lib/model/featuresModel/axisModel.js +1 -1
  16. package/lib/model/featuresModel/legendModel/legendModel.d.ts +0 -2
  17. package/lib/model/featuresModel/legendModel/legendModel.js +2 -3
  18. package/lib/model/marginModel.js +6 -5
  19. package/lib/model/modelBuilder.js +7 -7
  20. package/lib/model/modelInstance/canvasModel/canvasModel.d.ts +2 -0
  21. package/lib/model/modelInstance/canvasModel/canvasModel.js +2 -0
  22. package/lib/model/modelInstance/canvasModel/legendCanvasModel.d.ts +7 -0
  23. package/lib/model/modelInstance/canvasModel/legendCanvasModel.js +13 -0
  24. package/lib/model/modelInstance/dataModel.d.ts +11 -0
  25. package/lib/model/modelInstance/dataModel.js +23 -0
  26. package/lib/model/modelInstance/modelInstance.d.ts +3 -0
  27. package/lib/model/modelInstance/modelInstance.js +7 -1
  28. package/lib/model/notations/intervalModel.js +2 -3
  29. package/lib/model/notations/polarModel.d.ts +4 -0
  30. package/lib/model/notations/polarModel.js +13 -2
  31. package/lib/model/notations/twoDimensionalModel.js +1 -2
  32. package/package.json +1 -1
@@ -61,6 +61,7 @@ export interface Legend {
61
61
  export interface DataOptions {
62
62
  dataSource: string;
63
63
  keyField: MdtChartsField;
64
+ maxRecordsAmount?: number;
64
65
  }
65
66
  export interface MdtChartsField {
66
67
  name: string;
@@ -0,0 +1,28 @@
1
+ import { Block } from "../../block/block";
2
+ export interface RecordOverflowAlertOptions {
3
+ hidedRecordsAmount: number;
4
+ text: RecordOverflowAlertText;
5
+ positionAttrs: AlertBlockPositionAttrs;
6
+ }
7
+ export interface RecordOverflowAlertText {
8
+ one: string;
9
+ twoToFour: string;
10
+ tenToTwenty: string;
11
+ other: string;
12
+ }
13
+ export interface AlertBlockPositionAttrs {
14
+ top?: string;
15
+ bottom?: string;
16
+ right?: string;
17
+ left?: string;
18
+ }
19
+ declare class RecordOverflowAlertCoreClass {
20
+ private readonly blockClass;
21
+ render(block: Block, options: RecordOverflowAlertOptions): void;
22
+ update(block: Block, options: RecordOverflowAlertOptions): void;
23
+ private getAlertText;
24
+ private getWordTextEndingByAmount;
25
+ private setAlertPosition;
26
+ }
27
+ export declare const RecordOverflowAlertCore: RecordOverflowAlertCoreClass;
28
+ export {};
@@ -0,0 +1,50 @@
1
+ class RecordOverflowAlertCoreClass {
2
+ constructor() {
3
+ this.blockClass = 'record-overflow-alert';
4
+ }
5
+ render(block, options) {
6
+ const alertBlock = block.getWrapper()
7
+ .append('div')
8
+ .attr('class', this.blockClass)
9
+ .text(this.getAlertText(options));
10
+ this.setAlertPosition(alertBlock, options.positionAttrs);
11
+ }
12
+ update(block, options) {
13
+ let alertBlock = block.getWrapper()
14
+ .select(`div.${this.blockClass}`);
15
+ if (alertBlock.empty()) {
16
+ if (options.hidedRecordsAmount === 0)
17
+ return;
18
+ else
19
+ this.render(block, options);
20
+ }
21
+ else {
22
+ if (options.hidedRecordsAmount === 0)
23
+ alertBlock.remove();
24
+ else
25
+ alertBlock.text(this.getAlertText(options));
26
+ }
27
+ }
28
+ getAlertText(options) {
29
+ return `+ ${options.hidedRecordsAmount} ${this.getWordTextEndingByAmount(options.hidedRecordsAmount, options.text)}`;
30
+ }
31
+ getWordTextEndingByAmount(hidedRecordsAmount, text) {
32
+ const lastDigit = hidedRecordsAmount % 10;
33
+ if (hidedRecordsAmount >= 10 && hidedRecordsAmount <= 20)
34
+ return text.tenToTwenty;
35
+ if (lastDigit === 1)
36
+ return text.one;
37
+ if (lastDigit >= 2 && lastDigit <= 4)
38
+ return text.twoToFour;
39
+ return text.other;
40
+ }
41
+ setAlertPosition(alertBlock, attrs) {
42
+ alertBlock
43
+ .style('position', 'absolute')
44
+ .style('left', attrs.left)
45
+ .style('right', attrs.right)
46
+ .style('top', attrs.top)
47
+ .style('bottom', attrs.bottom);
48
+ }
49
+ }
50
+ export const RecordOverflowAlertCore = new RecordOverflowAlertCoreClass();
@@ -1,7 +1,6 @@
1
1
  import { Axis } from "../features/axis/axis";
2
2
  import { GridLine } from "../features/gridLine/gridLine";
3
3
  import { Legend } from "../features/legend/legend";
4
- import { RecordOverflowAlert } from "../features/recordOverflowAlert/recordOverflowAlert";
5
4
  import { Scale } from "../features/scale/scale";
6
5
  import { Title } from "../features/title/title";
7
6
  import { Tooltip } from "../features/tolltip/tooltip";
@@ -17,8 +16,6 @@ export class IntervalManager {
17
16
  Title.render(block, options.title, model.otherComponents.titleBlock, model.blockCanvas.size);
18
17
  Legend.render(block, data, options, model);
19
18
  Tooltip.render(block, model, data, model.otherComponents.tooltipBlock, scales);
20
- if (model.dataSettings.scope.hidedRecordsAmount !== 0)
21
- RecordOverflowAlert.render(block, model.dataSettings.scope.hidedRecordsAmount, 'top', options.orient);
22
19
  }
23
20
  static renderCharts(block, charts, scales, data, dataOptions, margin, keyAxisOrient, chartSettings) {
24
21
  block.renderChartsBlock();
@@ -0,0 +1,16 @@
1
+ import { LegendPosition } from "../../../model/model";
2
+ import { Block } from "../../block/block";
3
+ interface PolarRecordOverflowAlertOptions {
4
+ hidedRecordsAmount: number;
5
+ legendPosition: LegendPosition;
6
+ }
7
+ declare class PolarRecordOverflowAlertClass {
8
+ private readonly text;
9
+ render(block: Block, options: PolarRecordOverflowAlertOptions): void;
10
+ update(block: Block, options: PolarRecordOverflowAlertOptions): void;
11
+ private buildCoreOptions;
12
+ private getPositionAttrs;
13
+ private getLeftAttrForRightBlock;
14
+ }
15
+ export declare const PolarRecordOverflowAlert: PolarRecordOverflowAlertClass;
16
+ export {};
@@ -0,0 +1,48 @@
1
+ import { Legend } from "../../features/legend/legend";
2
+ import { RecordOverflowAlertCore } from "../../features/recordOverflowAlert/recordOverflowAlertCore";
3
+ import { DomHelper } from "../../helpers/domHelper";
4
+ class PolarRecordOverflowAlertClass {
5
+ constructor() {
6
+ this.text = {
7
+ one: 'категория',
8
+ twoToFour: 'категории',
9
+ tenToTwenty: 'категорий',
10
+ other: 'категорий'
11
+ };
12
+ }
13
+ render(block, options) {
14
+ RecordOverflowAlertCore.render(block, this.buildCoreOptions(block, options));
15
+ }
16
+ update(block, options) {
17
+ RecordOverflowAlertCore.update(block, this.buildCoreOptions(block, options));
18
+ }
19
+ buildCoreOptions(block, options) {
20
+ return {
21
+ hidedRecordsAmount: options.hidedRecordsAmount,
22
+ text: this.text,
23
+ positionAttrs: this.getPositionAttrs(block, options)
24
+ };
25
+ }
26
+ getPositionAttrs(block, options) {
27
+ const position = options.legendPosition === 'off' ? 'bottom' : options.legendPosition;
28
+ if (position === 'right') {
29
+ return {
30
+ bottom: '20px',
31
+ left: this.getLeftAttrForRightBlock(block) + 'px'
32
+ };
33
+ }
34
+ if (position === 'bottom') {
35
+ return {
36
+ bottom: '20px',
37
+ left: '20px'
38
+ };
39
+ }
40
+ }
41
+ getLeftAttrForRightBlock(block) {
42
+ const legendBlock = block.getSvg().select(`.${Legend.objectClass}`);
43
+ if (legendBlock.empty())
44
+ return 17;
45
+ return DomHelper.getSelectionNumericAttr(legendBlock, 'x');
46
+ }
47
+ }
48
+ export const PolarRecordOverflowAlert = new PolarRecordOverflowAlertClass();
@@ -1,10 +1,10 @@
1
1
  import { Legend } from "../features/legend/legend";
2
- import { RecordOverflowAlert } from "../features/recordOverflowAlert/recordOverflowAlert";
3
2
  import { Title } from "../features/title/title";
4
3
  import { ElementHighlighter } from "../elementHighlighter/elementHighlighter";
5
4
  import { Tooltip } from "../features/tolltip/tooltip";
6
5
  import { Aggregator } from "../features/aggregator/aggregator";
7
6
  import { Donut } from "./donut/donut";
7
+ import { PolarRecordOverflowAlert } from "./extenders/polarRecordOverflowAlert";
8
8
  export class PolarManager {
9
9
  static render(engine, model) {
10
10
  const options = model.options;
@@ -14,8 +14,11 @@ export class PolarManager {
14
14
  Legend.render(engine.block, engine.data, options, model);
15
15
  Tooltip.render(engine.block, model, engine.data, model.otherComponents.tooltipBlock);
16
16
  engine.block.filterEventManager.setListenerPolar(model.chartBlock.margin, model.blockCanvas.size, options);
17
- if (model.dataSettings.scope.hidedRecordsAmount !== 0 && model.options.legend.position !== 'off')
18
- RecordOverflowAlert.render(engine.block, model.dataSettings.scope.hidedRecordsAmount, model.options.legend.position);
17
+ if (model.dataSettings.scope.hidedRecordsAmount !== 0)
18
+ PolarRecordOverflowAlert.render(engine.block, {
19
+ hidedRecordsAmount: model.dataSettings.scope.hidedRecordsAmount,
20
+ legendPosition: model.options.legend.position
21
+ });
19
22
  engine.block.getSvg()
20
23
  .on('click', (e) => {
21
24
  if (e.target === engine.block.getSvg().node())
@@ -38,8 +41,10 @@ export class PolarManager {
38
41
  });
39
42
  Aggregator.update(block, data[options.data.dataSource], options.charts[0].data.valueField, options.chartCanvas.aggregator);
40
43
  Legend.update(block, data, model);
41
- if (model.options.legend.position !== 'off')
42
- RecordOverflowAlert.update(block, model.dataSettings.scope.hidedRecordsAmount, model.options.legend.position);
44
+ PolarRecordOverflowAlert.update(block, {
45
+ hidedRecordsAmount: model.dataSettings.scope.hidedRecordsAmount,
46
+ legendPosition: model.options.legend.position
47
+ });
43
48
  }
44
49
  static updateColors(block, model) {
45
50
  Legend.updateColors(block, model.options);
@@ -0,0 +1,15 @@
1
+ import { ChartOrientation } from "../../../config/config";
2
+ import { Block } from "../../block/block";
3
+ interface TwoDimRecordOverflowAlertOptions {
4
+ hidedRecordsAmount: number;
5
+ chartOrientation: ChartOrientation;
6
+ }
7
+ declare class TwoDimRecordOverflowAlertClass {
8
+ render(block: Block, options: TwoDimRecordOverflowAlertOptions): void;
9
+ update(block: Block, options: TwoDimRecordOverflowAlertOptions): void;
10
+ private buildCoreOptions;
11
+ private getText;
12
+ private getPositionAttrs;
13
+ }
14
+ export declare const TwoDimRecordOverflowAlert: TwoDimRecordOverflowAlertClass;
15
+ export {};
@@ -0,0 +1,32 @@
1
+ import { RecordOverflowAlertCore } from "../../features/recordOverflowAlert/recordOverflowAlertCore";
2
+ class TwoDimRecordOverflowAlertClass {
3
+ render(block, options) {
4
+ RecordOverflowAlertCore.render(block, this.buildCoreOptions(options));
5
+ }
6
+ update(block, options) {
7
+ RecordOverflowAlertCore.update(block, this.buildCoreOptions(options));
8
+ }
9
+ buildCoreOptions(options) {
10
+ return {
11
+ hidedRecordsAmount: options.hidedRecordsAmount,
12
+ text: this.getText(options.chartOrientation),
13
+ positionAttrs: this.getPositionAttrs()
14
+ };
15
+ }
16
+ getText(chartOrientation) {
17
+ const isHorizontal = chartOrientation === 'horizontal';
18
+ return {
19
+ one: isHorizontal ? 'строка' : 'столбец',
20
+ twoToFour: isHorizontal ? 'строки' : 'столбца',
21
+ tenToTwenty: isHorizontal ? 'строк' : 'столбцов',
22
+ other: isHorizontal ? 'строк' : 'столбцов'
23
+ };
24
+ }
25
+ getPositionAttrs() {
26
+ return {
27
+ right: '17px',
28
+ top: '1rem'
29
+ };
30
+ }
31
+ }
32
+ export const TwoDimRecordOverflowAlert = new TwoDimRecordOverflowAlertClass();
@@ -3,7 +3,6 @@ import { Axis } from "../features/axis/axis";
3
3
  import { EmbeddedLabels } from "../features/embeddedLabels/embeddedLabels";
4
4
  import { GridLine } from "../features/gridLine/gridLine";
5
5
  import { Legend } from "../features/legend/legend";
6
- import { RecordOverflowAlert } from "../features/recordOverflowAlert/recordOverflowAlert";
7
6
  import { Scale } from "../features/scale/scale";
8
7
  import { TipBox } from "../features/tipBox/tipBox";
9
8
  import { Title } from "../features/title/title";
@@ -12,6 +11,7 @@ import { Helper } from "../helpers/helper";
12
11
  import { Area } from "./area/area";
13
12
  import { Bar } from "./bar/bar";
14
13
  import { BarHelper } from "./bar/barHelper";
14
+ import { TwoDimRecordOverflowAlert } from "./extenders/twoDimRecordOverflowAlert";
15
15
  import { Line } from "./line/line";
16
16
  export class TwoDimensionalManager {
17
17
  static render(engine, model) {
@@ -28,7 +28,10 @@ export class TwoDimensionalManager {
28
28
  Legend.render(engine.block, engine.data, options, model);
29
29
  Tooltip.render(engine.block, model, engine.data, model.otherComponents.tooltipBlock, scales);
30
30
  if (model.dataSettings.scope.hidedRecordsAmount !== 0)
31
- RecordOverflowAlert.render(engine.block, model.dataSettings.scope.hidedRecordsAmount, 'top', options.orient);
31
+ TwoDimRecordOverflowAlert.render(engine.block, {
32
+ hidedRecordsAmount: model.dataSettings.scope.hidedRecordsAmount,
33
+ chartOrientation: options.orient
34
+ });
32
35
  engine.block.getSvg()
33
36
  .on('click', (e) => {
34
37
  if (e.target === engine.block.getSvg().node())
@@ -54,7 +57,10 @@ export class TwoDimensionalManager {
54
57
  block.filterEventManager.registerEventFor2D(scales.key, model.chartBlock.margin, model.blockCanvas.size, options);
55
58
  Tooltip.render(block, model, data, model.otherComponents.tooltipBlock, scales);
56
59
  });
57
- RecordOverflowAlert.update(block, model.dataSettings.scope.hidedRecordsAmount, 'top', options.orient);
60
+ TwoDimRecordOverflowAlert.update(block, {
61
+ hidedRecordsAmount: model.dataSettings.scope.hidedRecordsAmount,
62
+ chartOrientation: options.orient
63
+ });
58
64
  }
59
65
  static updateColors(block, model) {
60
66
  Legend.updateColors(block, model.options);
@@ -0,0 +1,26 @@
1
+ import { MdtChartsConfig, MdtChartsDataSource } from "../../config/config";
2
+ import { DesignerConfig } from "../../designer/designerConfig";
3
+ import { LegendBlockModel } from "../model";
4
+ import { ModelInstance } from "../modelInstance/modelInstance";
5
+ export declare class DataManagerModel {
6
+ private static service;
7
+ static getPreparedData(data: MdtChartsDataSource, allowableKeys: string[], config: MdtChartsConfig): MdtChartsDataSource;
8
+ static initDataScope(config: MdtChartsConfig, data: MdtChartsDataSource, designerConfig: DesignerConfig, legendBlock: LegendBlockModel, modelInstance: ModelInstance): void;
9
+ static getDataValuesByKeyField(data: MdtChartsDataSource, dataSourceName: string, keyFieldName: string): string[];
10
+ private static initDataScopeFor2D;
11
+ private static initDataScopeForPolar;
12
+ private static getMaximumPossibleScope;
13
+ private static limitAllowableKeys;
14
+ /**
15
+ * Выводит количество элементов (преимущественно баров) в одной группе. Группа - один ключ
16
+ * @param configOptions
17
+ * @param chartsLength
18
+ */
19
+ private static getElementsInGroupAmount;
20
+ private static getBarChartsInGroupAmount;
21
+ private static getScopedData;
22
+ private static getScopedChartData;
23
+ private static setDataType;
24
+ private static getTypedData;
25
+ private static getDataLimitByItemSize;
26
+ }
@@ -0,0 +1,132 @@
1
+ import { AxisModel } from "../featuresModel/axisModel";
2
+ import { LegendCanvasModel } from "../featuresModel/legendModel/legendCanvasModel";
3
+ import { ModelHelper } from "../modelHelper";
4
+ import { MIN_DONUT_BLOCK_SIZE, PolarModel } from "../notations/polarModel";
5
+ import { DataManagerModelService } from "./dataManagerModelService";
6
+ export class DataManagerModel {
7
+ static getPreparedData(data, allowableKeys, config) {
8
+ const scopedData = this.getScopedData(data, allowableKeys, config);
9
+ this.setDataType(scopedData, config);
10
+ return scopedData;
11
+ }
12
+ static initDataScope(config, data, designerConfig, legendBlock, modelInstance) {
13
+ if (config.options.type === '2d' || config.options.type === 'interval') {
14
+ this.initDataScopeFor2D(config.options, modelInstance, data, designerConfig);
15
+ }
16
+ else if (config.options.type === 'polar') {
17
+ this.initDataScopeForPolar(config.options, modelInstance, data, legendBlock, designerConfig.canvas.legendBlock);
18
+ }
19
+ }
20
+ static getDataValuesByKeyField(data, dataSourceName, keyFieldName) {
21
+ return data[dataSourceName].map(dataRow => dataRow[keyFieldName]);
22
+ }
23
+ static initDataScopeFor2D(configOptions, modelInstance, data, designerConfig) {
24
+ // Для interval всегда один элемент, так как там может быть только один столбик
25
+ let itemsLength = 1;
26
+ if (configOptions.type === '2d') {
27
+ itemsLength = (configOptions.charts)
28
+ .filter((chart) => chart.type === 'bar').length;
29
+ if (itemsLength === 0)
30
+ itemsLength = 1; // Если баров нет, то для одной записи выделяется столько же места, сколько для одного столбика
31
+ }
32
+ if (itemsLength !== 0) {
33
+ const axisLength = AxisModel.getAxisLength(configOptions.orientation, modelInstance.canvasModel);
34
+ const uniqueKeys = ModelHelper.getUniqueValues(data[configOptions.data.dataSource].map(d => d[configOptions.data.keyField.name]));
35
+ const dataLength = uniqueKeys.length;
36
+ const limit = this.getDataLimitByItemSize(this.getElementsInGroupAmount(configOptions, itemsLength), dataLength, axisLength, designerConfig.canvas.chartOptions.bar);
37
+ const allowableKeys = uniqueKeys.slice(0, limit);
38
+ const hidedRecordsAmount = dataLength - allowableKeys.length;
39
+ modelInstance.dataModel.initScope(this.limitAllowableKeys(allowableKeys, hidedRecordsAmount, modelInstance.dataModel));
40
+ }
41
+ else {
42
+ const allKeys = this.getDataValuesByKeyField(data, configOptions.data.dataSource, configOptions.data.keyField.name);
43
+ modelInstance.dataModel.initScope(this.getMaximumPossibleScope(allKeys, modelInstance.dataModel));
44
+ }
45
+ }
46
+ static initDataScopeForPolar(configOptions, modelInstance, data, legendBlock, legendCanvas) {
47
+ const canvas = modelInstance.canvasModel;
48
+ const dataset = data[configOptions.data.dataSource];
49
+ const keyFieldName = configOptions.data.keyField.name;
50
+ const keys = dataset.map(dataRow => dataRow[keyFieldName]);
51
+ if (!configOptions.legend.show) {
52
+ modelInstance.dataModel.initScope(this.getMaximumPossibleScope(keys, modelInstance.dataModel));
53
+ return;
54
+ }
55
+ const position = PolarModel.getLegendPositionByBlockSize(modelInstance.canvasModel);
56
+ let maxItemsNumber;
57
+ if (position === 'right') {
58
+ maxItemsNumber = LegendCanvasModel.findElementsAmountByLegendSize(keys, position, legendCanvas.maxWidth, canvas.getChartBlockHeight());
59
+ }
60
+ else {
61
+ const margin = canvas.getMargin();
62
+ const marginBottomWithoutLegendBlock = margin.bottom - (legendBlock.coordinate.bottom.size === 0 ? legendBlock.coordinate.bottom.size : legendBlock.coordinate.bottom.size - legendBlock.coordinate.bottom.margin.bottom);
63
+ maxItemsNumber = LegendCanvasModel.findElementsAmountByLegendSize(keys, position, canvas.getChartBlockWidth(), canvas.getBlockSize().height - margin.top - marginBottomWithoutLegendBlock - legendBlock.coordinate.bottom.margin.bottom - MIN_DONUT_BLOCK_SIZE);
64
+ }
65
+ const allowableKeys = keys.slice(0, maxItemsNumber);
66
+ const hidedRecordsAmount = keys.length - maxItemsNumber;
67
+ modelInstance.dataModel.initScope(this.limitAllowableKeys(allowableKeys, hidedRecordsAmount, modelInstance.dataModel));
68
+ }
69
+ static getMaximumPossibleScope(keys, dataModel) {
70
+ return this.service.getMaximumPossibleAmount(keys, dataModel.getMaxRecordsAmount());
71
+ }
72
+ static limitAllowableKeys(allowableKeys, hidedRecordsAmount, dataModel) {
73
+ return this.service.limitAllowableKeys(allowableKeys, hidedRecordsAmount, dataModel.getMaxRecordsAmount());
74
+ }
75
+ /**
76
+ * Выводит количество элементов (преимущественно баров) в одной группе. Группа - один ключ
77
+ * @param configOptions
78
+ * @param chartsLength
79
+ */
80
+ static getElementsInGroupAmount(configOptions, chartsLength) {
81
+ if (configOptions.type === '2d')
82
+ return this.getBarChartsInGroupAmount(configOptions.charts);
83
+ return chartsLength;
84
+ }
85
+ static getBarChartsInGroupAmount(charts) {
86
+ let barsAmount = 0;
87
+ charts.forEach(chart => {
88
+ if (chart.type === 'bar' && chart.isSegmented)
89
+ barsAmount += 1; // в сегментированном баре все valueFields находятся внутри одного бара, поэтому бар всегда один.
90
+ else if (chart.type === 'bar')
91
+ barsAmount += chart.data.valueFields.length;
92
+ });
93
+ return barsAmount;
94
+ }
95
+ static getScopedData(data, allowableKeys, config) {
96
+ const newData = {};
97
+ newData[config.options.data.dataSource] = this.getScopedChartData(data[config.options.data.dataSource], allowableKeys, config.options.data.keyField.name);
98
+ return newData;
99
+ }
100
+ static getScopedChartData(data, allowableKeys, keyFieldName) {
101
+ return data.filter(d => allowableKeys.findIndex(key => key === d[keyFieldName]) !== -1);
102
+ }
103
+ static setDataType(data, config) {
104
+ if (config.options.type === 'interval') {
105
+ const chart = config.options.chart;
106
+ if (chart.data.valueField1.format === 'date') {
107
+ data[config.options.data.dataSource] = this.getTypedData(data[config.options.data.dataSource], chart.data.valueField1);
108
+ }
109
+ if (chart.data.valueField2.format === 'date') {
110
+ data[config.options.data.dataSource] = this.getTypedData(data[config.options.data.dataSource], chart.data.valueField2);
111
+ }
112
+ }
113
+ }
114
+ static getTypedData(data, field) {
115
+ if (field.format === 'date')
116
+ data.forEach(d => {
117
+ d[field.name] = new Date(d[field.name]);
118
+ });
119
+ return data;
120
+ }
121
+ static getDataLimitByItemSize(elementsInGroupAmount, dataLength, axisLength, barOptions) {
122
+ let sumSize = dataLength * (elementsInGroupAmount * barOptions.minBarWidth + (elementsInGroupAmount - 1) * barOptions.barDistance + barOptions.groupMinDistance);
123
+ while (dataLength !== 0 && axisLength < sumSize) {
124
+ dataLength--;
125
+ // find whole space for bars in group + distance between bars + group distance
126
+ sumSize = dataLength * (elementsInGroupAmount * barOptions.minBarWidth + (elementsInGroupAmount - 1)
127
+ * barOptions.barDistance + barOptions.groupMinDistance);
128
+ }
129
+ return dataLength;
130
+ }
131
+ }
132
+ DataManagerModel.service = new DataManagerModelService();
@@ -0,0 +1,5 @@
1
+ import { DataScope } from "../model";
2
+ export declare class DataManagerModelService {
3
+ getMaximumPossibleAmount(keys: string[], maxPossibleAmount: number): DataScope;
4
+ limitAllowableKeys(allowableKeys: string[], hidedRecordsAmount: number, globalRecordsMaxAmount: number): DataScope;
5
+ }
@@ -0,0 +1,28 @@
1
+ export class DataManagerModelService {
2
+ getMaximumPossibleAmount(keys, maxPossibleAmount) {
3
+ if (maxPossibleAmount >= keys.length) {
4
+ return {
5
+ allowableKeys: keys,
6
+ hidedRecordsAmount: 0
7
+ };
8
+ }
9
+ else {
10
+ return {
11
+ allowableKeys: keys.slice(0, maxPossibleAmount),
12
+ hidedRecordsAmount: keys.length - maxPossibleAmount
13
+ };
14
+ }
15
+ }
16
+ limitAllowableKeys(allowableKeys, hidedRecordsAmount, globalRecordsMaxAmount) {
17
+ if (allowableKeys.length <= globalRecordsMaxAmount) {
18
+ return {
19
+ allowableKeys,
20
+ hidedRecordsAmount
21
+ };
22
+ }
23
+ return {
24
+ allowableKeys: allowableKeys.slice(0, globalRecordsMaxAmount),
25
+ hidedRecordsAmount: hidedRecordsAmount + allowableKeys.length - globalRecordsMaxAmount
26
+ };
27
+ }
28
+ }
@@ -1,6 +1,6 @@
1
1
  import { ModelHelper } from "../modelHelper";
2
2
  import { AxisType, CLASSES } from "../modelBuilder";
3
- import { DataManagerModel } from "../dataManagerModel";
3
+ import { DataManagerModel } from "../dataManagerModel/dataManagerModel";
4
4
  import { TwoDimensionalModel } from "../notations/twoDimensionalModel";
5
5
  export class AxisModel {
6
6
  static getKeyAxis(charts, data, dataOptions, orient, axisConfig, labelConfig, canvasModel, tooltipSettings) {
@@ -2,8 +2,6 @@ import { ChartNotation, Size } from "../../../config/config";
2
2
  import { ILegendModel, LegendBlockModel, LegendPosition, Orient } from "../../model";
3
3
  import { CanvasModel } from "../../modelInstance/canvasModel/canvasModel";
4
4
  import { LegendItemsDirection } from "./legendCanvasModel";
5
- /** If donut block has width less than this const, legend change postion from "right" to "bottom" */
6
- export declare const MIN_DONUT_BLOCK_SIZE = 260;
7
5
  export declare class LegendModel {
8
6
  static getLegendSize(chartNotation: ChartNotation, position: Orient, texts: string[], legendMaxWidth: number, blockSize: Size, legendBlockModel: LegendBlockModel): number;
9
7
  static getBaseLegendBlockModel(notation: ChartNotation, canvasModel: CanvasModel): LegendBlockModel;
@@ -1,7 +1,6 @@
1
1
  import { ModelHelper } from "../../modelHelper";
2
+ import { PolarModel } from "../../notations/polarModel";
2
3
  import { LegendCanvasModel } from "./legendCanvasModel";
3
- /** If donut block has width less than this const, legend change postion from "right" to "bottom" */
4
- export const MIN_DONUT_BLOCK_SIZE = 260;
5
4
  export class LegendModel {
6
5
  static getLegendSize(chartNotation, position, texts, legendMaxWidth, blockSize, legendBlockModel) {
7
6
  if (position === 'left' || position === 'right')
@@ -48,7 +47,7 @@ export class LegendModel {
48
47
  if (chartNotation === '2d' || chartNotation === 'interval')
49
48
  legendPosition = 'top';
50
49
  else if (chartNotation === 'polar') {
51
- legendPosition = canvasModel.getChartBlockWidth() < MIN_DONUT_BLOCK_SIZE ? 'bottom' : 'right';
50
+ legendPosition = PolarModel.getLegendPositionByBlockSize(canvasModel);
52
51
  }
53
52
  }
54
53
  return {
@@ -1,8 +1,9 @@
1
1
  import { AxisModel } from "./featuresModel/axisModel";
2
- import { DataManagerModel } from "./dataManagerModel";
3
- import { LegendModel, MIN_DONUT_BLOCK_SIZE } from "./featuresModel/legendModel/legendModel";
2
+ import { DataManagerModel } from "./dataManagerModel/dataManagerModel";
3
+ import { LegendModel } from "./featuresModel/legendModel/legendModel";
4
4
  import { AxisType } from "./modelBuilder";
5
5
  import { TwoDimensionalModel } from "./notations/twoDimensionalModel";
6
+ import { PolarModel } from "./notations/polarModel";
6
7
  export const AXIS_HORIZONTAL_LABEL_PADDING = 15;
7
8
  export const AXIS_VERTICAL_LABEL_PADDING = 10;
8
9
  export class MarginModel {
@@ -25,10 +26,9 @@ export class MarginModel {
25
26
  }
26
27
  static recalcPolarMarginWithScopedData(modelInstance, designerConfig, config, legendBlockModel, dataScope, options) {
27
28
  const canvasModel = modelInstance.canvasModel;
28
- let position = LegendModel.getLegendModel(config.options.type, config.options.legend.show, modelInstance.canvasModel).position;
29
+ let position = canvasModel.legendCanvas.getPosition();
29
30
  if (position !== 'off') {
30
- if (position === 'right' && canvasModel.getChartBlockWidth() < MIN_DONUT_BLOCK_SIZE)
31
- position = 'bottom';
31
+ position = PolarModel.getLegendPositionByBlockSize(canvasModel); // reset position
32
32
  this.clearMarginByLegendBlockPosition(canvasModel, legendBlockModel);
33
33
  let allowableKeys = [...dataScope.allowableKeys];
34
34
  if (dataScope.hidedRecordsAmount !== 0 && position === 'bottom')
@@ -82,6 +82,7 @@ export class MarginModel {
82
82
  static recalcMarginWithLegend(modelInstance, config, legendMaxWidth, legendBlockModel, data) {
83
83
  const canvasModel = modelInstance.canvasModel;
84
84
  const legendPosition = LegendModel.getLegendModel(config.options.type, config.options.legend.show, modelInstance.canvasModel).position;
85
+ modelInstance.canvasModel.legendCanvas.setPosition(legendPosition);
85
86
  if (legendPosition !== 'off') {
86
87
  const legendItemsContent = this.getLegendItemsContent(config.options, data);
87
88
  const legendSize = LegendModel.getLegendSize(config.options.type, legendPosition, legendItemsContent, legendMaxWidth, canvasModel.getBlockSize(), legendBlockModel);
@@ -1,7 +1,7 @@
1
1
  import { MarginModel } from './marginModel';
2
2
  import { TwoDimensionalModel } from './notations/twoDimensionalModel';
3
3
  import { PolarModel } from './notations/polarModel';
4
- import { DataManagerModel } from './dataManagerModel';
4
+ import { DataManagerModel } from './dataManagerModel/dataManagerModel';
5
5
  import { IntervalModel } from './notations/intervalModel';
6
6
  import { OtherComponentsModel } from './featuresModel/otherComponents';
7
7
  import { ConfigValidator } from './configsValidator/configValidator';
@@ -69,17 +69,17 @@ export function assembleModel(config, data, designerConfig) {
69
69
  resetFalsyValues(data, config.options.data.keyField.name);
70
70
  const otherComponents = OtherComponentsModel.getOtherComponentsModel({ elementsOptions: designerConfig.elementsOptions, notation: config.options.type, title: config.options.title }, modelInstance);
71
71
  MarginModel.initMargin(designerConfig, config, otherComponents, data, modelInstance);
72
- const dataScope = DataManagerModel.getDataScope(config, data, designerConfig, otherComponents.legendBlock, modelInstance);
73
- const preparedData = DataManagerModel.getPreparedData(data, dataScope.allowableKeys, config);
72
+ DataManagerModel.initDataScope(config, data, designerConfig, otherComponents.legendBlock, modelInstance);
73
+ const preparedData = DataManagerModel.getPreparedData(data, modelInstance.dataModel.getAllowableKeys(), config);
74
74
  if (config.options.type === '2d' && config.options.axis.key.visibility)
75
- MarginModel.recalcMarginByVerticalAxisLabel(modelInstance, config, designerConfig, dataScope);
75
+ MarginModel.recalcMarginByVerticalAxisLabel(modelInstance, config, designerConfig, modelInstance.dataModel.getScope());
76
76
  const blockCanvas = getBlockCanvas(config, modelInstance);
77
77
  const chartBlock = getChartBlockModel(modelInstance);
78
- const options = getOptions(config, designerConfig, modelInstance, dataScope, preparedData);
79
- const dataSettings = getDataSettings(dataScope, designerConfig);
78
+ const options = getOptions(config, designerConfig, modelInstance, modelInstance.dataModel.getScope(), preparedData);
79
+ const dataSettings = getDataSettings(modelInstance.dataModel.getScope(), designerConfig);
80
80
  const transitions = getTransitions(designerConfig);
81
81
  if (options.type === 'polar')
82
- MarginModel.recalcPolarMarginWithScopedData(modelInstance, designerConfig, config, otherComponents.legendBlock, dataScope, options);
82
+ MarginModel.recalcPolarMarginWithScopedData(modelInstance, designerConfig, config, otherComponents.legendBlock, modelInstance.dataModel.getScope(), options);
83
83
  modelInstance.canvasModel.roundMargin();
84
84
  return {
85
85
  blockCanvas,
@@ -1,9 +1,11 @@
1
1
  import { Size } from "../../../config/config";
2
2
  import { BlockMargin } from "../../model";
3
+ import { LegendCanvasModelInstance } from "./legendCanvasModel";
3
4
  import { TitleCanvasModel } from "./titleCanvas";
4
5
  declare type MarginSide = keyof BlockMargin;
5
6
  export declare class CanvasModel {
6
7
  titleCanvas: TitleCanvasModel;
8
+ legendCanvas: LegendCanvasModelInstance;
7
9
  private blockSize;
8
10
  private margin;
9
11
  constructor();
@@ -1,7 +1,9 @@
1
+ import { LegendCanvasModelInstance } from "./legendCanvasModel";
1
2
  import { TitleCanvasModel } from "./titleCanvas";
2
3
  export class CanvasModel {
3
4
  constructor() {
4
5
  this.titleCanvas = new TitleCanvasModel();
6
+ this.legendCanvas = new LegendCanvasModelInstance();
5
7
  }
6
8
  initMargin(margin) {
7
9
  this.margin = margin;
@@ -0,0 +1,7 @@
1
+ import { ILegendModel, LegendPosition } from "../../model";
2
+ export declare class LegendCanvasModelInstance {
3
+ private position;
4
+ getModel(): ILegendModel;
5
+ getPosition(): LegendPosition;
6
+ setPosition(position: LegendPosition): void;
7
+ }
@@ -0,0 +1,13 @@
1
+ export class LegendCanvasModelInstance {
2
+ getModel() {
3
+ return {
4
+ position: this.position
5
+ };
6
+ }
7
+ getPosition() {
8
+ return this.position;
9
+ }
10
+ setPosition(position) {
11
+ this.position = position;
12
+ }
13
+ }
@@ -0,0 +1,11 @@
1
+ import { DataScope } from "../model";
2
+ export declare const DEFAULT_MAX_RECORDS_AMOUNT = 50;
3
+ export declare class DataModelInstance {
4
+ private maxRecordsAmount;
5
+ private scope;
6
+ initMaxRecordsAmount(amount: number): void;
7
+ getMaxRecordsAmount(): number;
8
+ initScope(scope: DataScope): void;
9
+ getScope(): DataScope;
10
+ getAllowableKeys(): string[];
11
+ }
@@ -0,0 +1,23 @@
1
+ export const DEFAULT_MAX_RECORDS_AMOUNT = 50;
2
+ export class DataModelInstance {
3
+ constructor() {
4
+ this.maxRecordsAmount = DEFAULT_MAX_RECORDS_AMOUNT;
5
+ }
6
+ initMaxRecordsAmount(amount) {
7
+ if (typeof amount === "number" && amount > 0) {
8
+ this.maxRecordsAmount = amount;
9
+ }
10
+ }
11
+ getMaxRecordsAmount() {
12
+ return this.maxRecordsAmount;
13
+ }
14
+ initScope(scope) {
15
+ this.scope = scope;
16
+ }
17
+ getScope() {
18
+ return this.scope;
19
+ }
20
+ getAllowableKeys() {
21
+ return this.getScope().allowableKeys;
22
+ }
23
+ }
@@ -1,7 +1,10 @@
1
1
  import { MdtChartsConfig } from "../../main";
2
2
  import { CanvasModel } from "./canvasModel/canvasModel";
3
+ import { DataModelInstance } from "./dataModel";
3
4
  export declare class ModelInstance {
4
5
  static create(config: MdtChartsConfig): ModelInstance;
6
+ private static initInitialParams;
5
7
  canvasModel: CanvasModel;
8
+ dataModel: DataModelInstance;
6
9
  constructor();
7
10
  }
@@ -1,11 +1,17 @@
1
1
  import { CanvasModel } from "./canvasModel/canvasModel";
2
+ import { DataModelInstance } from "./dataModel";
2
3
  export class ModelInstance {
3
4
  constructor() {
4
5
  this.canvasModel = new CanvasModel();
6
+ this.dataModel = new DataModelInstance();
5
7
  }
6
8
  static create(config) {
7
9
  const modelInstance = new ModelInstance();
8
- modelInstance.canvasModel.initBlockSize(config.canvas.size);
10
+ this.initInitialParams(modelInstance, config);
9
11
  return modelInstance;
10
12
  }
13
+ static initInitialParams(modelInstance, config) {
14
+ modelInstance.canvasModel.initBlockSize(config.canvas.size);
15
+ modelInstance.dataModel.initMaxRecordsAmount(config.options.data.maxRecordsAmount);
16
+ }
11
17
  }
@@ -1,7 +1,6 @@
1
1
  import { AxisModel } from "../featuresModel/axisModel";
2
2
  import { ChartStyleModelService } from "../chartStyleModel/chartStyleModel";
3
- import { DataManagerModel } from "../dataManagerModel";
4
- import { LegendModel } from "../featuresModel/legendModel/legendModel";
3
+ import { DataManagerModel } from "../dataManagerModel/dataManagerModel";
5
4
  import { AxisType } from "../modelBuilder";
6
5
  import { ScaleModel, ScaleType } from "../featuresModel/scaleModel";
7
6
  import { TwoDimensionalModel } from "./twoDimensionalModel";
@@ -10,7 +9,7 @@ export class IntervalModel {
10
9
  const options = config.options;
11
10
  const canvasModel = modelInstance.canvasModel;
12
11
  return {
13
- legend: LegendModel.getLegendModel(config.options.type, config.options.legend.show, canvasModel),
12
+ legend: canvasModel.legendCanvas.getModel(),
14
13
  title: options.title,
15
14
  selectable: !!options.selectable,
16
15
  orient: options.orientation,
@@ -1,9 +1,13 @@
1
1
  import { MdtChartsDataSource, MdtChartsPolarOptions } from "../../config/config";
2
2
  import { DesignerConfig } from "../../designer/designerConfig";
3
3
  import { PolarOptionsModel } from "../model";
4
+ import { CanvasModel } from "../modelInstance/canvasModel/canvasModel";
4
5
  import { ModelInstance } from "../modelInstance/modelInstance";
6
+ /** If donut block has width less than this const, legend change postion from "right" to "bottom" */
7
+ export declare const MIN_DONUT_BLOCK_SIZE = 120;
5
8
  export declare class PolarModel {
6
9
  static getOptions(options: MdtChartsPolarOptions, data: MdtChartsDataSource, designerConfig: DesignerConfig, modelInstance: ModelInstance): PolarOptionsModel;
10
+ static getLegendPositionByBlockSize(canvasModel: CanvasModel): "bottom" | "right";
7
11
  private static getDonutSettings;
8
12
  private static getChartsModel;
9
13
  }
@@ -1,5 +1,6 @@
1
1
  import { ChartStyleModelService } from "../chartStyleModel/chartStyleModel";
2
- import { LegendModel } from "../featuresModel/legendModel/legendModel";
2
+ /** If donut block has width less than this const, legend change postion from "right" to "bottom" */
3
+ export const MIN_DONUT_BLOCK_SIZE = 120;
3
4
  export class PolarModel {
4
5
  static getOptions(options, data, designerConfig, modelInstance) {
5
6
  return {
@@ -8,11 +9,21 @@ export class PolarModel {
8
9
  title: options.title,
9
10
  data: Object.assign({}, options.data),
10
11
  charts: this.getChartsModel(options.chart, data[options.data.dataSource].length, designerConfig.chartStyle),
11
- legend: LegendModel.getLegendModel(options.type, options.legend.show, modelInstance.canvasModel),
12
+ legend: modelInstance.canvasModel.legendCanvas.getModel(),
12
13
  tooltip: options.tooltip,
13
14
  chartCanvas: this.getDonutSettings(designerConfig.canvas.chartOptions.donut, options.chart)
14
15
  };
15
16
  }
17
+ //TODO: type for returned value
18
+ static getLegendPositionByBlockSize(canvasModel) {
19
+ const widthCoefficientWhenLegendShouldInBottom = 1.5;
20
+ const blockWidth = canvasModel.getBlockSize().width;
21
+ const blockHeight = canvasModel.getBlockSize().height;
22
+ return canvasModel.getChartBlockWidth() < MIN_DONUT_BLOCK_SIZE
23
+ && blockWidth * widthCoefficientWhenLegendShouldInBottom < blockHeight
24
+ ? 'bottom'
25
+ : 'right';
26
+ }
16
27
  static getDonutSettings(settings, chartOptions) {
17
28
  return {
18
29
  padAngle: settings.padAngle,
@@ -1,13 +1,12 @@
1
1
  import { ChartStyleModelService } from "../chartStyleModel/chartStyleModel";
2
2
  import { TwoDimensionalChartStyleModel } from "../chartStyleModel/TwoDimensionalChartStyleModel";
3
3
  import { AxisModel } from "../featuresModel/axisModel";
4
- import { LegendModel } from "../featuresModel/legendModel/legendModel";
5
4
  import { ScaleModel } from "../featuresModel/scaleModel";
6
5
  export class TwoDimensionalModel {
7
6
  static getOptions(options, designerConfig, dataScope, data, modelInstance) {
8
7
  const canvasModel = modelInstance.canvasModel;
9
8
  return {
10
- legend: LegendModel.getLegendModel(options.type, options.legend.show, canvasModel),
9
+ legend: canvasModel.legendCanvas.getModel(),
11
10
  title: options.title,
12
11
  selectable: !!options.selectable,
13
12
  orient: options.orientation,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mdt-charts",
3
- "version": "1.11.1",
3
+ "version": "1.12.0",
4
4
  "description": "",
5
5
  "main": "lib/main.js",
6
6
  "scripts": {