mdt-charts 1.13.2 → 1.14.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.
- package/README.md +1 -189
- package/lib/config/config.d.ts +28 -6
- package/lib/designer/designerConfig.d.ts +20 -2
- package/lib/engine/block/blockSvg.d.ts +3 -1
- package/lib/engine/block/blockSvg.js +8 -3
- package/lib/engine/block/defs.d.ts +7 -0
- package/lib/engine/block/defs.js +18 -0
- package/lib/engine/cardsNotation/card/cardService.js +2 -2
- package/lib/engine/elementHighlighter/elementHighlighter.js +2 -1
- package/lib/engine/features/axis/axis.js +6 -3
- package/lib/engine/features/axis/axisHelper.d.ts +2 -2
- package/lib/engine/features/axis/axisHelper.js +6 -11
- package/lib/engine/features/axis/axisLabelDomHelper.js +9 -11
- package/lib/engine/features/legend/legend.d.ts +17 -12
- package/lib/engine/features/legend/legend.js +38 -22
- package/lib/engine/features/legend/legendDomHelper.d.ts +8 -4
- package/lib/engine/features/legend/legendDomHelper.js +20 -8
- package/lib/engine/features/legend/legendEventsManager.d.ts +2 -2
- package/lib/engine/features/legend/legendEventsManager.js +5 -5
- package/lib/engine/features/legend/legendHelper.d.ts +6 -3
- package/lib/engine/features/legend/legendHelper.js +5 -7
- package/lib/engine/features/legend/legendMarkerCreator.d.ts +21 -0
- package/lib/engine/features/legend/legendMarkerCreator.js +88 -0
- package/lib/engine/features/legend/legendWidthCalculator.d.ts +16 -0
- package/lib/engine/features/legend/legendWidthCalculator.js +119 -0
- package/lib/engine/features/tolltip/tooltip.js +2 -5
- package/lib/engine/features/tolltip/tooltipDomHelper.d.ts +4 -4
- package/lib/engine/features/tolltip/tooltipDomHelper.js +13 -26
- package/lib/engine/helpers/domHelper.js +1 -1
- package/lib/engine/helpers/pipeline/Pipeline.d.ts +9 -0
- package/lib/engine/helpers/pipeline/Pipeline.js +37 -0
- package/lib/engine/intervalNotation/intervalManager.js +0 -2
- package/lib/engine/polarNotation/polarManager.js +3 -3
- package/lib/engine/twoDimensionalNotation/bar/bar.d.ts +16 -13
- package/lib/engine/twoDimensionalNotation/bar/bar.js +30 -18
- package/lib/engine/twoDimensionalNotation/bar/barHelper.d.ts +3 -0
- package/lib/engine/twoDimensionalNotation/bar/barHelper.js +9 -0
- package/lib/engine/twoDimensionalNotation/line/line.d.ts +22 -11
- package/lib/engine/twoDimensionalNotation/line/line.js +33 -17
- package/lib/engine/twoDimensionalNotation/line/lineGenerator.d.ts +15 -0
- package/lib/engine/twoDimensionalNotation/line/lineGenerator.js +27 -0
- package/lib/engine/twoDimensionalNotation/line/lineHelper.d.ts +18 -4
- package/lib/engine/twoDimensionalNotation/line/lineHelper.js +26 -16
- package/lib/engine/twoDimensionalNotation/twoDimensionalManager.js +13 -12
- package/lib/model/featuresModel/axisModel.d.ts +2 -1
- package/lib/model/featuresModel/axisModel.js +11 -1
- package/lib/model/featuresModel/legendModel/legendModel.d.ts +2 -1
- package/lib/model/featuresModel/legendModel/legendModel.js +5 -1
- package/lib/model/featuresModel/otherComponents.d.ts +2 -1
- package/lib/model/featuresModel/otherComponents.js +1 -1
- package/lib/model/featuresModel/scaleModel/scaleModel.d.ts +2 -1
- package/lib/model/featuresModel/scaleModel/scaleModel.js +4 -2
- package/lib/model/margin/marginModel.d.ts +6 -3
- package/lib/model/margin/marginModel.js +12 -8
- package/lib/model/margin/twoDim/twoDimMarginModel.d.ts +6 -3
- package/lib/model/margin/twoDim/twoDimMarginModel.js +30 -29
- package/lib/model/model.d.ts +56 -4
- package/lib/model/model.js +7 -1
- package/lib/model/modelBuilder.js +11 -6
- package/lib/model/modelInstance/configReader.d.ts +19 -0
- package/lib/model/modelInstance/configReader.js +35 -0
- package/lib/model/modelInstance/dataModel/dataModel.d.ts +2 -2
- package/lib/model/modelInstance/dataModel/dataModel.js +0 -1
- package/lib/model/modelInstance/dataModel/dataRepository.d.ts +6 -2
- package/lib/model/modelInstance/dataModel/dataRepository.js +15 -2
- package/lib/model/modelInstance/modelInstance.d.ts +2 -1
- package/lib/model/modelInstance/modelInstance.js +6 -4
- package/lib/model/notations/cards/cardsChangeService.js +2 -2
- package/lib/model/notations/cards/cardsModelService.js +1 -1
- package/lib/model/notations/intervalModel.js +4 -3
- package/lib/model/notations/polar/polarModel.js +6 -1
- package/lib/model/notations/twoDimensional/styles.d.ts +6 -0
- package/lib/model/notations/twoDimensional/styles.js +41 -0
- package/lib/model/notations/twoDimensionalModel.d.ts +5 -5
- package/lib/model/notations/twoDimensionalModel.js +13 -8
- package/lib/style/charts-main.css +3 -0
- package/lib/style/charts-main.less +3 -0
- package/package.json +5 -5
- package/lib/engine/contentManager.d.ts +0 -9
- package/lib/engine/contentManager.js +0 -29
- package/lib/model/modelInstance/canvasModel/marginModelService.d.ts +0 -11
- package/lib/model/modelInstance/canvasModel/marginModelService.js +0 -26
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import { ValueFormatter, } from "../../valueFormatter";
|
|
2
2
|
import { TooltipHelper } from './tooltipHelper';
|
|
3
3
|
import { Helper } from '../../helpers/helper';
|
|
4
|
+
import { getMarkerCreator } from '../legend/legendMarkerCreator';
|
|
4
5
|
export const ARROW_SIZE = 20;
|
|
5
6
|
export const ARROW_DEFAULT_POSITION = 9;
|
|
6
7
|
export const TOOLTIP_ARROW_PADDING_X = ARROW_DEFAULT_POSITION - (ARROW_SIZE * Math.sqrt(2) - ARROW_SIZE) / 2 + 14;
|
|
7
8
|
export const TOOLTIP_ARROW_PADDING_Y = 13;
|
|
8
9
|
export class TooltipDomHelper {
|
|
9
|
-
static
|
|
10
|
+
static fillForMulti2DCharts(contentBlock, charts, data, dataOptions, keyValue, htmlHandler) {
|
|
10
11
|
contentBlock.html('');
|
|
11
12
|
if (!htmlHandler) {
|
|
12
13
|
this.renderHead(contentBlock, keyValue);
|
|
13
14
|
charts.forEach(chart => {
|
|
14
15
|
chart.data.valueFields.forEach((field, index) => {
|
|
15
16
|
const html = this.getTooltipItemHtml(data, dataOptions, keyValue, field);
|
|
16
|
-
this.fillValuesContent(contentBlock, chart.style.elementColors[index % chart.style.elementColors.length], html);
|
|
17
|
+
this.fillValuesContent(contentBlock, chart.style.elementColors[index % chart.style.elementColors.length], html, this.getMarkerCreator(chart.legend));
|
|
17
18
|
});
|
|
18
19
|
});
|
|
19
20
|
}
|
|
@@ -26,22 +27,7 @@ export class TooltipDomHelper {
|
|
|
26
27
|
if (!htmlHandler) {
|
|
27
28
|
this.renderHead(contentBlock, keyValue);
|
|
28
29
|
const html = this.getTooltipItemHtml(data, dataOptions, keyValue, chart.data.valueField);
|
|
29
|
-
this.fillValuesContent(contentBlock, markColor, html);
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
this.fillContentByFunction(contentBlock, data, dataOptions, keyValue, htmlHandler);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
static fillForIntervalChart(contentBlock, charts, data, dataOptions, keyValue, htmlHandler) {
|
|
36
|
-
contentBlock.html('');
|
|
37
|
-
if (!htmlHandler) {
|
|
38
|
-
this.renderHead(contentBlock, keyValue);
|
|
39
|
-
charts.forEach(chart => {
|
|
40
|
-
let html = this.getTooltipItemHtml(data, dataOptions, keyValue, chart.data.valueField1);
|
|
41
|
-
this.fillValuesContent(contentBlock, chart.style.elementColors[0 % chart.style.elementColors.length], html);
|
|
42
|
-
html = this.getTooltipItemHtml(data, dataOptions, keyValue, chart.data.valueField2);
|
|
43
|
-
this.fillValuesContent(contentBlock, chart.style.elementColors[0 % chart.style.elementColors.length], html);
|
|
44
|
-
});
|
|
30
|
+
this.fillValuesContent(contentBlock, markColor, html, this.getMarkerCreator(chart.legend));
|
|
45
31
|
}
|
|
46
32
|
else {
|
|
47
33
|
this.fillContentByFunction(contentBlock, data, dataOptions, keyValue, htmlHandler);
|
|
@@ -60,15 +46,13 @@ export class TooltipDomHelper {
|
|
|
60
46
|
.attr('class', `${this.groupClass} ${this.headClass}`)
|
|
61
47
|
.text(keyValue);
|
|
62
48
|
}
|
|
63
|
-
static fillValuesContent(contentBlock, markColor, tooltipHtml) {
|
|
49
|
+
static fillValuesContent(contentBlock, markColor, tooltipHtml, markerCreator) {
|
|
64
50
|
const group = contentBlock.append('div')
|
|
65
51
|
.attr('class', this.groupClass);
|
|
66
|
-
if (markColor)
|
|
67
|
-
group.append('div')
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
.attr('class', 'tooltip-circle')
|
|
71
|
-
.style('background-color', markColor);
|
|
52
|
+
if (markColor) {
|
|
53
|
+
const colorBlock = group.append('div').attr('class', 'tooltip-color');
|
|
54
|
+
markerCreator === null || markerCreator === void 0 ? void 0 : markerCreator.renderMarker(colorBlock, markColor);
|
|
55
|
+
}
|
|
72
56
|
group.append('div')
|
|
73
57
|
.attr('class', 'tooltip-texts')
|
|
74
58
|
.append('div')
|
|
@@ -96,8 +80,11 @@ export class TooltipDomHelper {
|
|
|
96
80
|
static setWhiteSpaceForTextBlocks(contentBlock) {
|
|
97
81
|
contentBlock.selectAll(`.${this.textItemClass}`).style('white-space', 'pre-wrap');
|
|
98
82
|
}
|
|
83
|
+
static getMarkerCreator(options) {
|
|
84
|
+
return getMarkerCreator(options, { default: { cssClass: TooltipDomHelper.tooltipLegendDefaultMarker } });
|
|
85
|
+
}
|
|
99
86
|
}
|
|
100
87
|
TooltipDomHelper.groupClass = 'tooltip-group';
|
|
101
88
|
TooltipDomHelper.headClass = 'tooltip-head';
|
|
102
89
|
TooltipDomHelper.textItemClass = 'tooltip-text-item';
|
|
103
|
-
TooltipDomHelper.
|
|
90
|
+
TooltipDomHelper.tooltipLegendDefaultMarker = 'tooltip-circle';
|
|
@@ -15,7 +15,7 @@ export class DomHelper {
|
|
|
15
15
|
if (chart.type === 'line' || chart.type === 'area')
|
|
16
16
|
return MarkDot.getMarkDotForChart(block, chart.cssClasses);
|
|
17
17
|
else
|
|
18
|
-
return Bar.getAllBarsForChart(block, chart.cssClasses);
|
|
18
|
+
return Bar.get().getAllBarsForChart(block, chart.cssClasses);
|
|
19
19
|
}
|
|
20
20
|
static getCssPropertyValue(node, propertyName) {
|
|
21
21
|
return window.getComputedStyle(node).getPropertyValue(propertyName);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
declare type Middleware<D, M> = (args: D, meta?: M) => D | undefined;
|
|
2
|
+
export declare class Pipeline<D = any, M = any> {
|
|
3
|
+
private middlewaresStorage;
|
|
4
|
+
constructor(middlewares?: Middleware<D, M>[]);
|
|
5
|
+
push(middleware: Middleware<D, M>): () => void;
|
|
6
|
+
remove(middleware: Middleware<D, M>): void;
|
|
7
|
+
execute<CurrentArgs extends D = D>(args: CurrentArgs, meta?: M): CurrentArgs;
|
|
8
|
+
}
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export class Pipeline {
|
|
2
|
+
constructor(middlewares) {
|
|
3
|
+
this.middlewaresStorage = new PipelineMiddlewaresStorage(middlewares);
|
|
4
|
+
}
|
|
5
|
+
push(middleware) {
|
|
6
|
+
return this.middlewaresStorage.push(middleware);
|
|
7
|
+
}
|
|
8
|
+
remove(middleware) {
|
|
9
|
+
this.middlewaresStorage.remove(middleware);
|
|
10
|
+
}
|
|
11
|
+
execute(args, meta) {
|
|
12
|
+
const process = (args, middlewares) => {
|
|
13
|
+
const current = middlewares[0];
|
|
14
|
+
if (!current) {
|
|
15
|
+
return args;
|
|
16
|
+
}
|
|
17
|
+
const replaceArgs = current(args, meta);
|
|
18
|
+
return process(replaceArgs === undefined ? args : replaceArgs, middlewares.slice(1));
|
|
19
|
+
};
|
|
20
|
+
return process(args, this.middlewaresStorage.getList());
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
class PipelineMiddlewaresStorage {
|
|
24
|
+
constructor(middlewares) {
|
|
25
|
+
this.middlewares = middlewares || [];
|
|
26
|
+
}
|
|
27
|
+
push(middleware) {
|
|
28
|
+
this.middlewares.push(middleware);
|
|
29
|
+
return () => this.remove(middleware);
|
|
30
|
+
}
|
|
31
|
+
remove(middleware) {
|
|
32
|
+
this.middlewares = this.middlewares.filter((cur) => cur != middleware);
|
|
33
|
+
}
|
|
34
|
+
getList() {
|
|
35
|
+
return this.middlewares;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Axis } from "../features/axis/axis";
|
|
2
2
|
import { GridLine } from "../features/gridLine/gridLine";
|
|
3
|
-
import { Legend } from "../features/legend/legend";
|
|
4
3
|
import { Scale } from "../features/scale/scale";
|
|
5
4
|
import { Title } from "../features/title/title";
|
|
6
5
|
import { Gantt } from "./gantt";
|
|
@@ -13,7 +12,6 @@ export class IntervalManager {
|
|
|
13
12
|
GridLine.render(block, options.additionalElements.gridLine.flag, options.axis, model.blockCanvas.size, model.chartBlock.margin, scales);
|
|
14
13
|
this.renderCharts(block, options.charts, scales, data, options.data, model.chartBlock.margin, options.axis.key.orient, options.chartSettings);
|
|
15
14
|
Title.render(block, options.title, model.otherComponents.titleBlock, model.blockCanvas.size);
|
|
16
|
-
Legend.render(block, data, options, model);
|
|
17
15
|
}
|
|
18
16
|
static renderCharts(block, charts, scales, data, dataOptions, margin, keyAxisOrient, chartSettings) {
|
|
19
17
|
block.svg.renderChartsBlock();
|
|
@@ -11,7 +11,7 @@ export class PolarManager {
|
|
|
11
11
|
engine.block.svg.render(model.blockCanvas.size);
|
|
12
12
|
this.renderCharts(engine.block, options.charts, engine.data, options.data.dataSource, model.chartBlock.margin, model.blockCanvas.size, options.chartCanvas);
|
|
13
13
|
Title.render(engine.block, options.title, model.otherComponents.titleBlock, model.blockCanvas.size);
|
|
14
|
-
Legend.render(engine.block, engine.data, options, model);
|
|
14
|
+
Legend.get().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
17
|
if (model.dataSettings.scope.hidedRecordsAmount !== 0)
|
|
@@ -40,14 +40,14 @@ export class PolarManager {
|
|
|
40
40
|
block.filterEventManager.setListenerPolar(model.chartBlock.margin, model.blockCanvas.size, options);
|
|
41
41
|
});
|
|
42
42
|
Aggregator.update(block, options.charts[0].data.valueField, options.chartCanvas.aggregator);
|
|
43
|
-
Legend.update(block, data, model);
|
|
43
|
+
Legend.get().update(block, data, model);
|
|
44
44
|
PolarRecordOverflowAlert.update(block, {
|
|
45
45
|
hidedRecordsAmount: model.dataSettings.scope.hidedRecordsAmount,
|
|
46
46
|
legendPosition: model.options.legend.position
|
|
47
47
|
});
|
|
48
48
|
}
|
|
49
49
|
updateColors(block, model) {
|
|
50
|
-
Legend.updateColors(block, model.options);
|
|
50
|
+
Legend.get().updateColors(block, model.options);
|
|
51
51
|
Donut.updateColors(block, model.options.charts[0]);
|
|
52
52
|
}
|
|
53
53
|
renderCharts(block, charts, data, dataSource, margin, blockSize, donutSettings) {
|
|
@@ -15,20 +15,23 @@ export interface RectElemWithAttrs extends SVGElement {
|
|
|
15
15
|
}
|
|
16
16
|
export declare class Bar {
|
|
17
17
|
static readonly barItemClass = "bar-item";
|
|
18
|
-
static
|
|
19
|
-
private
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
private
|
|
28
|
-
private
|
|
29
|
-
private
|
|
18
|
+
static get(): Bar;
|
|
19
|
+
private readonly barItemClass;
|
|
20
|
+
private readonly barSegmentGroupClass;
|
|
21
|
+
private createBarPipeline;
|
|
22
|
+
constructor();
|
|
23
|
+
render(block: Block, scales: Scales, data: MdtChartsDataRow[], keyField: Field, margin: BlockMargin, keyAxisOrient: Orient, chart: TwoDimensionalChartModel, blockSize: Size, barSettings: BarChartSettings, barsAmounts: number[], isSegmented: boolean, firstBarIndex: number): void;
|
|
24
|
+
update(block: Block, newData: MdtChartsDataRow[], scales: Scales, margin: BlockMargin, keyAxisOrient: Orient, chart: TwoDimensionalChartModel, blockSize: Size, barsAmounts: number[], keyField: Field, firstBarIndex: number, barSettings: BarChartSettings, isSegmented: boolean): Promise<any>[];
|
|
25
|
+
updateColors(block: Block, chart: TwoDimensionalChartModel): void;
|
|
26
|
+
getAllBarsForChart(block: Block, chartCssClasses: string[]): Selection<BaseType, MdtChartsDataRow, BaseType, unknown>;
|
|
27
|
+
private renderGrouped;
|
|
28
|
+
private renderSegmented;
|
|
29
|
+
private updateGrouped;
|
|
30
|
+
private updateSegmented;
|
|
31
|
+
private fillBarAttrs;
|
|
32
|
+
private setSegmentColor;
|
|
30
33
|
/**
|
|
31
34
|
* Устнановка координат для удобного обновления.
|
|
32
35
|
*/
|
|
33
|
-
private
|
|
36
|
+
private setInitialAttrsInfo;
|
|
34
37
|
}
|
|
@@ -1,19 +1,29 @@
|
|
|
1
1
|
import { select } from 'd3-selection';
|
|
2
2
|
import { EmbeddedLabels } from "../../features/embeddedLabels/embeddedLabels";
|
|
3
3
|
import { EmbeddedLabelsHelper } from "../../features/embeddedLabels/embeddedLabelsHelper";
|
|
4
|
-
import { BarHelper } from "./barHelper";
|
|
4
|
+
import { BarHelper, onBarChartInit } from "./barHelper";
|
|
5
5
|
import { sum } from "d3-array";
|
|
6
6
|
import { DomHelper } from "../../helpers/domHelper";
|
|
7
7
|
import { Helper } from "../../helpers/helper";
|
|
8
8
|
import { getStackedDataWithOwn } from './stackedData/dataStacker';
|
|
9
|
+
import { Pipeline } from '../../helpers/pipeline/Pipeline';
|
|
9
10
|
export class Bar {
|
|
10
|
-
|
|
11
|
+
constructor() {
|
|
12
|
+
this.barItemClass = Bar.barItemClass;
|
|
13
|
+
this.barSegmentGroupClass = 'bar-segment-group';
|
|
14
|
+
this.createBarPipeline = new Pipeline();
|
|
15
|
+
onBarChartInit(this.createBarPipeline);
|
|
16
|
+
}
|
|
17
|
+
static get() {
|
|
18
|
+
return new Bar();
|
|
19
|
+
}
|
|
20
|
+
render(block, scales, data, keyField, margin, keyAxisOrient, chart, blockSize, barSettings, barsAmounts, isSegmented, firstBarIndex) {
|
|
11
21
|
if (isSegmented)
|
|
12
22
|
this.renderSegmented(block, scales, data, keyField, margin, keyAxisOrient, chart, barsAmounts, blockSize, firstBarIndex, barSettings);
|
|
13
23
|
else
|
|
14
24
|
this.renderGrouped(block, scales, data, keyField, margin, keyAxisOrient, chart, barsAmounts, blockSize, firstBarIndex, barSettings);
|
|
15
25
|
}
|
|
16
|
-
|
|
26
|
+
update(block, newData, scales, margin, keyAxisOrient, chart, blockSize, barsAmounts, keyField, firstBarIndex, barSettings, isSegmented) {
|
|
17
27
|
let promises;
|
|
18
28
|
if (isSegmented) {
|
|
19
29
|
promises = this.updateSegmented(block, newData, scales, margin, keyAxisOrient, chart, blockSize, barsAmounts, keyField, firstBarIndex, barSettings);
|
|
@@ -23,25 +33,26 @@ export class Bar {
|
|
|
23
33
|
}
|
|
24
34
|
return promises;
|
|
25
35
|
}
|
|
26
|
-
|
|
36
|
+
updateColors(block, chart) {
|
|
27
37
|
chart.data.valueFields.forEach((_vf, index) => {
|
|
28
38
|
const bars = block.svg.getChartGroup(chart.index)
|
|
29
39
|
.selectAll(`.${this.barItemClass}${Helper.getCssClassesLine(chart.cssClasses)}${Helper.getCssClassesLine(Helper.getCssClassesWithElementIndex(chart.cssClasses, index))}`);
|
|
30
40
|
DomHelper.setChartStyle(bars, chart.style, index, 'fill');
|
|
31
41
|
});
|
|
32
42
|
}
|
|
33
|
-
|
|
43
|
+
getAllBarsForChart(block, chartCssClasses) {
|
|
34
44
|
return block.getSvg().selectAll(`rect.${this.barItemClass}${Helper.getCssClassesLine(chartCssClasses)}`);
|
|
35
45
|
}
|
|
36
|
-
|
|
46
|
+
renderGrouped(block, scales, data, keyField, margin, keyAxisOrient, chart, barsAmounts, blockSize, firstBarIndex, barSettings) {
|
|
37
47
|
chart.data.valueFields.forEach((field, index) => {
|
|
38
|
-
|
|
48
|
+
let bars = block.svg.getChartGroup(chart.index)
|
|
39
49
|
.selectAll(`.${this.barItemClass}${Helper.getCssClassesLine(chart.cssClasses)}${Helper.getCssClassesLine(Helper.getCssClassesWithElementIndex(chart.cssClasses, index))}`)
|
|
40
50
|
.data(data)
|
|
41
51
|
.enter()
|
|
42
52
|
.append('rect')
|
|
43
53
|
.attr('class', this.barItemClass)
|
|
44
54
|
.style('clip-path', `url(#${block.svg.getClipPathId()})`);
|
|
55
|
+
bars = this.createBarPipeline.execute(bars, chart);
|
|
45
56
|
const barAttrs = BarHelper.getGroupedBarAttrs(keyAxisOrient, scales, margin, keyField.name, field.name, blockSize, BarHelper.getBarIndex(barsAmounts, chart.index - firstBarIndex) + index, sum(barsAmounts), barSettings);
|
|
46
57
|
this.fillBarAttrs(bars, barAttrs);
|
|
47
58
|
DomHelper.setCssClasses(bars, Helper.getCssClassesWithElementIndex(chart.cssClasses, index));
|
|
@@ -51,7 +62,7 @@ export class Bar {
|
|
|
51
62
|
EmbeddedLabels.render(block, bars, barAttrs, EmbeddedLabelsHelper.getLabelField(chart.embeddedLabels, chart.data.valueFields, keyField, index), chart.embeddedLabels, keyAxisOrient, blockSize, margin, index, chart.cssClasses);
|
|
52
63
|
});
|
|
53
64
|
}
|
|
54
|
-
|
|
65
|
+
renderSegmented(block, scales, data, keyField, margin, keyAxisOrient, chart, barsAmounts, blockSize, firstBarIndex, barSettings) {
|
|
55
66
|
const stackedData = getStackedDataWithOwn(data, chart.data.valueFields.map(field => field.name));
|
|
56
67
|
let groups = block.svg.getChartGroup(chart.index)
|
|
57
68
|
.selectAll(`g.${this.barSegmentGroupClass}${Helper.getCssClassesLine(chart.cssClasses)}`)
|
|
@@ -62,13 +73,14 @@ export class Bar {
|
|
|
62
73
|
.enter()
|
|
63
74
|
.append('g')
|
|
64
75
|
.attr('class', this.barSegmentGroupClass);
|
|
65
|
-
|
|
76
|
+
let bars = groups
|
|
66
77
|
.selectAll(`rect${Helper.getCssClassesLine(chart.cssClasses)}`)
|
|
67
78
|
.data(d => d)
|
|
68
79
|
.enter()
|
|
69
80
|
.append('rect')
|
|
70
81
|
.attr('class', this.barItemClass)
|
|
71
82
|
.style('clip-path', `url(#${block.svg.getClipPathId()})`);
|
|
83
|
+
bars = this.createBarPipeline.execute(bars, chart);
|
|
72
84
|
const barAttrs = BarHelper.getStackedBarAttr(keyAxisOrient, scales, margin, keyField.name, blockSize, BarHelper.getBarIndex(barsAmounts, chart.index) - firstBarIndex, sum(barsAmounts), barSettings);
|
|
73
85
|
this.fillBarAttrs(bars, barAttrs);
|
|
74
86
|
this.setInitialAttrsInfo(bars, keyAxisOrient, barSettings);
|
|
@@ -80,7 +92,7 @@ export class Bar {
|
|
|
80
92
|
thisClass.setSegmentColor(select(this).selectAll(Helper.getCssClassesLine(chart.cssClasses)), chart.style.elementColors, i);
|
|
81
93
|
});
|
|
82
94
|
}
|
|
83
|
-
|
|
95
|
+
updateGrouped(block, newData, scales, margin, keyAxisOrient, chart, blockSize, barsAmounts, keyField, firstBarIndex, barSettings) {
|
|
84
96
|
const promises = [];
|
|
85
97
|
chart.data.valueFields.forEach((valueField, index) => {
|
|
86
98
|
const indexesOfRemoved = [];
|
|
@@ -102,11 +114,12 @@ export class Bar {
|
|
|
102
114
|
.filter(d => newData.findIndex(row => row[keyField.name] === d[keyField.name]) !== -1)
|
|
103
115
|
.style('opacity', 1)
|
|
104
116
|
.data(newData);
|
|
105
|
-
|
|
117
|
+
let newBars = bars
|
|
106
118
|
.enter()
|
|
107
119
|
.append('rect')
|
|
108
120
|
.attr('class', this.barItemClass)
|
|
109
121
|
.style('clip-path', `url(#${block.svg.getClipPathId()})`);
|
|
122
|
+
newBars = this.createBarPipeline.execute(newBars, chart);
|
|
110
123
|
const barAttrs = BarHelper.getGroupedBarAttrs(keyAxisOrient, scales, margin, keyField.name, valueField.name, blockSize, BarHelper.getBarIndex(barsAmounts, chart.index) + index - firstBarIndex, sum(barsAmounts), barSettings);
|
|
111
124
|
const prom = this.fillBarAttrs(bars, barAttrs, block.transitionManager.durations.chartUpdate)
|
|
112
125
|
.then(() => {
|
|
@@ -128,7 +141,7 @@ export class Bar {
|
|
|
128
141
|
});
|
|
129
142
|
return promises;
|
|
130
143
|
}
|
|
131
|
-
|
|
144
|
+
updateSegmented(block, newData, scales, margin, keyAxisOrient, chart, blockSize, barsAmounts, keyField, firstBarIndex, barSettings) {
|
|
132
145
|
const stackedData = getStackedDataWithOwn(newData, chart.data.valueFields.map(field => field.name));
|
|
133
146
|
block.svg.getChartGroup(chart.index)
|
|
134
147
|
.selectAll(`.${this.barItemClass}${Helper.getCssClassesLine(chart.cssClasses)}`)
|
|
@@ -145,10 +158,11 @@ export class Bar {
|
|
|
145
158
|
.filter(d => newData.findIndex(row => row[keyField.name] === d.data[keyField.name]) !== -1)
|
|
146
159
|
.style('opacity', 1)
|
|
147
160
|
.data(d => d);
|
|
148
|
-
|
|
161
|
+
let newBars = bars.enter()
|
|
149
162
|
.append('rect')
|
|
150
163
|
.attr('class', this.barItemClass)
|
|
151
164
|
.style('clip-path', `url(#${block.svg.getClipPathId()})`);
|
|
165
|
+
newBars = this.createBarPipeline.execute(newBars, chart);
|
|
152
166
|
const barAttrs = BarHelper.getStackedBarAttr(keyAxisOrient, scales, margin, keyField.name, blockSize, BarHelper.getBarIndex(barsAmounts, chart.index) - firstBarIndex, sum(barsAmounts), barSettings);
|
|
153
167
|
const prom = this.fillBarAttrs(bars, barAttrs, block.transitionManager.durations.chartUpdate)
|
|
154
168
|
.then(() => {
|
|
@@ -165,7 +179,7 @@ export class Bar {
|
|
|
165
179
|
});
|
|
166
180
|
return [prom];
|
|
167
181
|
}
|
|
168
|
-
|
|
182
|
+
fillBarAttrs(bars, barAttrs, transitionDuration = 0) {
|
|
169
183
|
return new Promise((resolve) => {
|
|
170
184
|
if (bars.size() === 0) {
|
|
171
185
|
resolve('');
|
|
@@ -187,13 +201,13 @@ export class Bar {
|
|
|
187
201
|
resolve('');
|
|
188
202
|
});
|
|
189
203
|
}
|
|
190
|
-
|
|
204
|
+
setSegmentColor(segments, colorPalette, segmentedIndex) {
|
|
191
205
|
segments.style('fill', colorPalette[segmentedIndex % colorPalette.length]);
|
|
192
206
|
}
|
|
193
207
|
/**
|
|
194
208
|
* Устнановка координат для удобного обновления.
|
|
195
209
|
*/
|
|
196
|
-
|
|
210
|
+
setInitialAttrsInfo(bars, keyAxisOrient, barSettings) {
|
|
197
211
|
bars.each(function () {
|
|
198
212
|
const width = DomHelper.getSelectionNumericAttr(select(this), 'width');
|
|
199
213
|
const height = DomHelper.getSelectionNumericAttr(select(this), 'height');
|
|
@@ -212,5 +226,3 @@ export class Bar {
|
|
|
212
226
|
}
|
|
213
227
|
}
|
|
214
228
|
Bar.barItemClass = 'bar-item';
|
|
215
|
-
Bar.barItemCloneClass = 'bar-item-clone';
|
|
216
|
-
Bar.barSegmentGroupClass = 'bar-segment-group';
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { BarChartSettings, BlockMargin, Orient, TwoDimensionalChartModel } from "../../../model/model";
|
|
2
2
|
import { Scales } from "../../features/scale/scale";
|
|
3
3
|
import { MdtChartsDataRow, Size } from "../../../config/config";
|
|
4
|
+
import { Pipeline } from "../../helpers/pipeline/Pipeline";
|
|
5
|
+
import { BaseType, Selection } from "d3-selection";
|
|
4
6
|
export interface BarAttrsHelper {
|
|
5
7
|
x: (dataRow: MdtChartsDataRow) => number;
|
|
6
8
|
y: (dataRow: MdtChartsDataRow) => number;
|
|
@@ -22,3 +24,4 @@ export declare class BarHelper {
|
|
|
22
24
|
private static setGroupedBarAttrsByValue;
|
|
23
25
|
private static setSegmentedBarAttrsByValue;
|
|
24
26
|
}
|
|
27
|
+
export declare function onBarChartInit(createBarPipeline: Pipeline<Selection<SVGRectElement, any, BaseType, any>, TwoDimensionalChartModel>): void;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Scale } from "../../features/scale/scale";
|
|
2
2
|
import { Helper } from "../../helpers/helper";
|
|
3
|
+
import { HatchPatternDef } from "../../block/defs";
|
|
3
4
|
export class BarHelper {
|
|
4
5
|
static getGroupedBarAttrs(keyAxisOrient, scales, margin, keyField, valueFieldName, blockSize, barIndex, barsAmount, barSettings) {
|
|
5
6
|
const attrs = {
|
|
@@ -101,3 +102,11 @@ export class BarHelper {
|
|
|
101
102
|
}
|
|
102
103
|
}
|
|
103
104
|
}
|
|
105
|
+
export function onBarChartInit(createBarPipeline) {
|
|
106
|
+
createBarPipeline.push(hatchBar);
|
|
107
|
+
}
|
|
108
|
+
function hatchBar(bars, chart) {
|
|
109
|
+
if (chart.barViewOptions.hatch.on)
|
|
110
|
+
bars.style("mask", HatchPatternDef.getMaskValue());
|
|
111
|
+
return bars;
|
|
112
|
+
}
|
|
@@ -1,17 +1,28 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BaseType, Selection } from 'd3-selection';
|
|
2
|
+
import { BlockMargin, Field, LineLikeChartSettings, Orient, TwoDimensionalChartModel } from "../../../model/model";
|
|
2
3
|
import { Scales } from "../../features/scale/scale";
|
|
3
4
|
import { Block } from "../../block/block";
|
|
4
5
|
import { MdtChartsDataRow } from '../../../config/config';
|
|
6
|
+
import { Pipeline } from '../../helpers/pipeline/Pipeline';
|
|
7
|
+
interface LineChartOptions {
|
|
8
|
+
staticSettings: LineLikeChartSettings;
|
|
9
|
+
}
|
|
5
10
|
export declare class Line {
|
|
11
|
+
private options;
|
|
6
12
|
static readonly lineChartClass = "line";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
static
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
private
|
|
15
|
-
private
|
|
16
|
-
private
|
|
13
|
+
readonly creatingPipeline: Pipeline<Selection<SVGPathElement, any, BaseType, any>, TwoDimensionalChartModel>;
|
|
14
|
+
private readonly lineChartClass;
|
|
15
|
+
static get(options: LineChartOptions): Line;
|
|
16
|
+
constructor(options: LineChartOptions);
|
|
17
|
+
render(block: Block, scales: Scales, data: MdtChartsDataRow[], keyField: Field, margin: BlockMargin, keyAxisOrient: Orient, chart: TwoDimensionalChartModel): void;
|
|
18
|
+
update(block: Block, scales: Scales, newData: MdtChartsDataRow[], keyField: Field, margin: BlockMargin, keyAxisOrient: Orient, chart: TwoDimensionalChartModel): Promise<any>[];
|
|
19
|
+
updateColors(block: Block, chart: TwoDimensionalChartModel): void;
|
|
20
|
+
private renderGrouped;
|
|
21
|
+
private renderSegmented;
|
|
22
|
+
private updateGrouped;
|
|
23
|
+
private updateSegmented;
|
|
24
|
+
private updateGroupedPath;
|
|
25
|
+
private updateSegmentedPath;
|
|
26
|
+
private setSegmentColor;
|
|
17
27
|
}
|
|
28
|
+
export {};
|
|
@@ -1,17 +1,27 @@
|
|
|
1
1
|
import { stack } from 'd3-shape';
|
|
2
2
|
import { select } from 'd3-selection';
|
|
3
3
|
import { MarkDot } from "../../features/markDots/markDot";
|
|
4
|
-
import {
|
|
4
|
+
import { LineGeneratorFactory, onLineChartInit } from './lineHelper';
|
|
5
5
|
import { DomHelper } from '../../helpers/domHelper';
|
|
6
6
|
import { Helper } from '../../helpers/helper';
|
|
7
|
+
import { Pipeline } from '../../helpers/pipeline/Pipeline';
|
|
7
8
|
export class Line {
|
|
8
|
-
|
|
9
|
+
constructor(options) {
|
|
10
|
+
this.options = options;
|
|
11
|
+
this.creatingPipeline = new Pipeline();
|
|
12
|
+
this.lineChartClass = Line.lineChartClass; //TODO: remove after refactor
|
|
13
|
+
onLineChartInit(this.creatingPipeline);
|
|
14
|
+
}
|
|
15
|
+
static get(options) {
|
|
16
|
+
return new Line(options);
|
|
17
|
+
}
|
|
18
|
+
render(block, scales, data, keyField, margin, keyAxisOrient, chart) {
|
|
9
19
|
if (chart.isSegmented)
|
|
10
20
|
this.renderSegmented(block, scales, data, keyField, margin, keyAxisOrient, chart);
|
|
11
21
|
else
|
|
12
22
|
this.renderGrouped(block, scales, data, keyField, margin, keyAxisOrient, chart);
|
|
13
23
|
}
|
|
14
|
-
|
|
24
|
+
update(block, scales, newData, keyField, margin, keyAxisOrient, chart) {
|
|
15
25
|
let promises;
|
|
16
26
|
if (chart.isSegmented) {
|
|
17
27
|
promises = this.updateSegmented(block, scales, newData, keyField, margin, keyAxisOrient, chart);
|
|
@@ -21,7 +31,7 @@ export class Line {
|
|
|
21
31
|
}
|
|
22
32
|
return promises;
|
|
23
33
|
}
|
|
24
|
-
|
|
34
|
+
updateColors(block, chart) {
|
|
25
35
|
chart.data.valueFields.forEach((_vf, valueIndex) => {
|
|
26
36
|
const path = block.svg.getChartGroup(chart.index)
|
|
27
37
|
.select(`.${this.lineChartClass}${Helper.getCssClassesLine(chart.cssClasses)}.chart-element-${valueIndex}`);
|
|
@@ -29,25 +39,28 @@ export class Line {
|
|
|
29
39
|
MarkDot.updateColors(block, chart, valueIndex);
|
|
30
40
|
});
|
|
31
41
|
}
|
|
32
|
-
|
|
42
|
+
renderGrouped(block, scales, data, keyField, margin, keyAxisOrient, chart) {
|
|
43
|
+
const generatorFactory = new LineGeneratorFactory({ keyAxisOrient, scales, keyFieldName: keyField.name, margin, curve: this.options.staticSettings.shape.curve.type });
|
|
33
44
|
chart.data.valueFields.forEach((valueField, valueIndex) => {
|
|
34
|
-
const lineGenerator =
|
|
35
|
-
|
|
45
|
+
const lineGenerator = generatorFactory.getLineGenerator(valueField.name);
|
|
46
|
+
let path = block.svg.getChartGroup(chart.index)
|
|
36
47
|
.append('path')
|
|
37
48
|
.attr('d', lineGenerator(data))
|
|
38
49
|
.attr('class', this.lineChartClass)
|
|
39
50
|
.style('fill', 'none')
|
|
40
51
|
.style('clip-path', `url(#${block.svg.getClipPathId()})`)
|
|
41
52
|
.style('pointer-events', 'none');
|
|
53
|
+
path = this.creatingPipeline.execute(path, chart);
|
|
42
54
|
DomHelper.setCssClasses(path, Helper.getCssClassesWithElementIndex(chart.cssClasses, valueIndex));
|
|
43
55
|
DomHelper.setChartStyle(path, chart.style, valueIndex, 'stroke');
|
|
44
56
|
MarkDot.render(block, data, keyAxisOrient, scales, margin, keyField.name, valueIndex, valueField.name, chart);
|
|
45
57
|
});
|
|
46
58
|
}
|
|
47
|
-
|
|
59
|
+
renderSegmented(block, scales, data, keyField, margin, keyAxisOrient, chart) {
|
|
48
60
|
const stackedData = stack().keys(chart.data.valueFields.map(field => field.name))(data);
|
|
49
|
-
const
|
|
50
|
-
const
|
|
61
|
+
const generatorFactory = new LineGeneratorFactory({ keyAxisOrient, scales, keyFieldName: keyField.name, margin, curve: this.options.staticSettings.shape.curve.type });
|
|
62
|
+
const lineGenerator = generatorFactory.getSegmentedLineGenerator();
|
|
63
|
+
let lines = block.svg.getChartGroup(chart.index)
|
|
51
64
|
.selectAll(`.${this.lineChartClass}${Helper.getCssClassesLine(chart.cssClasses)}`)
|
|
52
65
|
.data(stackedData)
|
|
53
66
|
.enter()
|
|
@@ -57,6 +70,7 @@ export class Line {
|
|
|
57
70
|
.style('fill', 'none')
|
|
58
71
|
.style('clip-path', `url(#${block.svg.getClipPathId()})`)
|
|
59
72
|
.style('pointer-events', 'none');
|
|
73
|
+
lines = this.creatingPipeline.execute(lines, chart);
|
|
60
74
|
lines.each(function (d, i) {
|
|
61
75
|
DomHelper.setCssClasses(select(this), Helper.getCssClassesWithElementIndex(chart.cssClasses, i));
|
|
62
76
|
});
|
|
@@ -65,10 +79,11 @@ export class Line {
|
|
|
65
79
|
MarkDot.render(block, dataset, keyAxisOrient, scales, margin, keyField.name, stackIndex, '1', chart);
|
|
66
80
|
});
|
|
67
81
|
}
|
|
68
|
-
|
|
82
|
+
updateGrouped(block, scales, newData, keyField, margin, keyAxisOrient, chart) {
|
|
69
83
|
const promises = [];
|
|
84
|
+
const generatorFactory = new LineGeneratorFactory({ keyAxisOrient, scales, keyFieldName: keyField.name, margin, curve: this.options.staticSettings.shape.curve.type });
|
|
70
85
|
chart.data.valueFields.forEach((valueField, valueFieldIndex) => {
|
|
71
|
-
const lineGenerator =
|
|
86
|
+
const lineGenerator = generatorFactory.getLineGenerator(valueField.name);
|
|
72
87
|
const lineObject = block.svg.getChartGroup(chart.index)
|
|
73
88
|
.select(`.${this.lineChartClass}${Helper.getCssClassesLine(chart.cssClasses)}.chart-element-${valueFieldIndex}`);
|
|
74
89
|
const prom = this.updateGroupedPath(block, lineObject, lineGenerator, newData);
|
|
@@ -77,9 +92,10 @@ export class Line {
|
|
|
77
92
|
});
|
|
78
93
|
return promises;
|
|
79
94
|
}
|
|
80
|
-
|
|
95
|
+
updateSegmented(block, scales, newData, keyField, margin, keyAxisOrient, chart) {
|
|
81
96
|
const stackedData = stack().keys(chart.data.valueFields.map(field => field.name))(newData);
|
|
82
|
-
const
|
|
97
|
+
const generatorFactory = new LineGeneratorFactory({ keyAxisOrient, scales, keyFieldName: keyField.name, margin, curve: this.options.staticSettings.shape.curve.type });
|
|
98
|
+
const lineGenerator = generatorFactory.getSegmentedLineGenerator();
|
|
83
99
|
const lines = block.svg.getChartGroup(chart.index)
|
|
84
100
|
.selectAll(`path.${this.lineChartClass}${Helper.getCssClassesLine(chart.cssClasses)}`)
|
|
85
101
|
.data(stackedData);
|
|
@@ -89,7 +105,7 @@ export class Line {
|
|
|
89
105
|
});
|
|
90
106
|
return [prom];
|
|
91
107
|
}
|
|
92
|
-
|
|
108
|
+
updateGroupedPath(block, lineObject, lineGenerator, newData) {
|
|
93
109
|
return new Promise(resolve => {
|
|
94
110
|
if (lineObject.size() === 0) {
|
|
95
111
|
resolve('');
|
|
@@ -107,7 +123,7 @@ export class Line {
|
|
|
107
123
|
resolve('');
|
|
108
124
|
});
|
|
109
125
|
}
|
|
110
|
-
|
|
126
|
+
updateSegmentedPath(block, linesObjects, lineGenerator) {
|
|
111
127
|
return new Promise(resolve => {
|
|
112
128
|
if (linesObjects.size() === 0) {
|
|
113
129
|
resolve('');
|
|
@@ -125,7 +141,7 @@ export class Line {
|
|
|
125
141
|
resolve('');
|
|
126
142
|
});
|
|
127
143
|
}
|
|
128
|
-
|
|
144
|
+
setSegmentColor(segments, colorPalette) {
|
|
129
145
|
segments.style('stroke', (d, i) => colorPalette[i % colorPalette.length]);
|
|
130
146
|
}
|
|
131
147
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Line as ILine } from "d3-shape";
|
|
2
|
+
import { MdtChartsDataRow } from "../../../config/config";
|
|
3
|
+
import { LineCurveType } from "../../../model/model";
|
|
4
|
+
interface LineGeneratorOptions {
|
|
5
|
+
curve?: LineCurveType;
|
|
6
|
+
}
|
|
7
|
+
declare type CoordinateGetter = (dataRow: MdtChartsDataRow) => number;
|
|
8
|
+
export declare class LineGenerator {
|
|
9
|
+
private options;
|
|
10
|
+
private readonly curvies;
|
|
11
|
+
constructor(options: LineGeneratorOptions);
|
|
12
|
+
get(xValue: CoordinateGetter, yValue: CoordinateGetter): ILine<MdtChartsDataRow>;
|
|
13
|
+
private setCurve;
|
|
14
|
+
}
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { curveBasis, curveMonotoneX, line, curveMonotoneY } from "d3-shape";
|
|
2
|
+
import { LineCurveType } from "../../../model/model";
|
|
3
|
+
export class LineGenerator {
|
|
4
|
+
constructor(options) {
|
|
5
|
+
this.options = options;
|
|
6
|
+
this.curvies = {
|
|
7
|
+
[LineCurveType.monotoneX]: curveMonotoneX,
|
|
8
|
+
[LineCurveType.monotoneY]: curveMonotoneY,
|
|
9
|
+
[LineCurveType.basis]: curveBasis,
|
|
10
|
+
[LineCurveType.none]: undefined
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
get(xValue, yValue) {
|
|
14
|
+
const generator = line()
|
|
15
|
+
.x(xValue)
|
|
16
|
+
.y(yValue);
|
|
17
|
+
this.setCurve(generator);
|
|
18
|
+
return generator;
|
|
19
|
+
}
|
|
20
|
+
setCurve(generator) {
|
|
21
|
+
if (this.options.curve != null) {
|
|
22
|
+
const curve = this.curvies[this.options.curve];
|
|
23
|
+
if (curve)
|
|
24
|
+
generator.curve(curve);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|