@datarailsshared/dr_renderer 1.2.5 → 1.2.6

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.
@@ -1,277 +0,0 @@
1
- const helpers = require("./dr-renderer-helpers");
2
-
3
- const DR_TOOLTIP_OPTIONS_DEFAULT = {
4
- anchorOffset: 10,
5
- arrowRadius: 3,
6
- arrowSize: 10,
7
- background: "#fff",
8
- border: 1,
9
- borderColor: "#DFE0E3",
10
- borderRadius: 8,
11
- boxShadow: "0px 4px 8px 1px rgba(0, 0, 0, 0.25)",
12
- direction: "top",
13
- followPointer: false,
14
- outerOffset: 8,
15
- paddings: [6, 12],
16
- showArrow: true,
17
- };
18
-
19
- function DrChartTooltip(chart, options) {
20
- this.getOptions = function() {
21
- return this.options;
22
- }
23
-
24
- this.add = function(content, anchor, options = {}) {
25
- const localOptions = Object.assign({}, this.options, options );
26
- let tooltip;
27
-
28
- if (!content || !anchor) {
29
- return false;
30
- }
31
-
32
- anchor.addEventListener("mouseover", (event) => {
33
- if (tooltip) {
34
- tooltip.destroy();
35
- }
36
- tooltip = this.create(content, localOptions.followPointer ? event : anchor, localOptions);
37
- tooltip.show();
38
- });
39
-
40
- anchor.addEventListener("mouseleave", (event) => {
41
- if (!tooltip) {
42
- return;
43
- }
44
-
45
- tooltip = tooltip.destroy();
46
- });
47
-
48
- if (localOptions.followPointer) {
49
- anchor.addEventListener("mousemove", (event) => {
50
- if (!tooltip) {
51
- return;
52
- }
53
-
54
- this.setTooltipPosition(tooltip, event, localOptions);
55
- });
56
- }
57
- }
58
-
59
- this.create = function(content, anchor, options) {
60
- const tooltip = this.chart.renderer
61
- .text(`${content}${options.showArrow ? `<span class="dr-renderer-tooltip_arrow" style="position: absolute"></span>` : ""}`, 0, 0, true)
62
- .attr({
63
- class: "dr-renderer-tooltip",
64
- })
65
- .css({
66
- background: options.background,
67
- border: `${options.border}px solid ${options.borderColor}`,
68
- borderRadius: options.borderRadius + "px",
69
- boxShadow: options.boxShadow,
70
- color: options.color,
71
- display: "flex",
72
- alignItems: "center",
73
- gap: "4px",
74
- fontFamily: options.fontFamily,
75
- fontSize: options.fontSize + "px",
76
- padding: options.paddings.map((p) => `${p}px`).join(" "),
77
- })
78
- .add()
79
- .hide();
80
-
81
- helpers.removeSVGTextCorrection(tooltip);
82
-
83
- this.setTooltipPosition(tooltip, anchor, options);
84
-
85
- return tooltip;
86
- }
87
-
88
- this.setTooltipPosition = function(tooltip, anchor, options) {
89
- const position = this.getPosition(tooltip, anchor, options);
90
-
91
- tooltip.attr({
92
- x: position.x,
93
- y: position.y,
94
- class: `dr-renderer-tooltip ${position.direction}`,
95
- });
96
-
97
- if (options.showArrow) {
98
- this.setArrowPosition(tooltip, position, anchor, options);
99
- }
100
- }
101
-
102
- this.setArrowPosition = function(tooltip, position, anchor, options) {
103
- const arrowEl = tooltip.element.querySelector(".dr-renderer-tooltip_arrow");
104
- const anchorBox = this.getAnchorBox(anchor);
105
- const tooltipBox = tooltip.getBBox();
106
- arrowEl.removeAttribute("style");
107
- const styles = {
108
- position: "absolute",
109
- display: "block",
110
- width: `${options.arrowSize}px`,
111
- height: `${options.arrowSize}px`,
112
- transform: "rotate(-45deg)",
113
- "border-style": "solid",
114
- "border-width": `${options.border}px`,
115
- background: options.background,
116
- };
117
-
118
- switch (position.direction) {
119
- case "top":
120
- Object.assign(styles, {
121
- "border-color": `transparent transparent ${options.borderColor} ${options.borderColor}`,
122
- "border-bottom-left-radius": `${options.arrowRadius}px`,
123
- bottom: `-${options.arrowSize / 2}px`,
124
- left: `${helpers.clamp(
125
- options.borderRadius,
126
- Math.max(anchorBox.x - position.x, 0) +
127
- Math.min(anchorBox.width, tooltipBox.width) / 2 -
128
- options.arrowSize / 2,
129
- tooltipBox.width - options.arrowSize - options.borderRadius
130
- )}px`,
131
- });
132
- break;
133
- case "bottom":
134
- Object.assign(styles, {
135
- "border-color": `${options.borderColor} ${options.borderColor} transparent transparent`,
136
- "border-top-right-radius": `${options.arrowRadius}px`,
137
- top: `-${options.arrowSize / 2}px`,
138
- left: `${helpers.clamp(
139
- options.borderRadius,
140
- Math.max(anchorBox.x - position.x, 0) +
141
- Math.min(anchorBox.width, tooltipBox.width) / 2 -
142
- options.arrowSize / 2,
143
- tooltipBox.width - options.arrowSize - options.borderRadius
144
- )}px`,
145
- });
146
- break;
147
- case "left":
148
- Object.assign(styles, {
149
- "border-color": `transparent ${options.borderColor} ${options.borderColor} transparent`,
150
- "border-bottom-right-radius": `${options.arrowRadius}px`,
151
- right: `-${options.arrowSize / 2}px`,
152
- top: `${helpers.clamp(
153
- options.borderRadius,
154
- Math.max(anchorBox.y - position.y, 0) +
155
- Math.min(anchorBox.height, tooltipBox.height) / 2 -
156
- options.arrowSize / 2,
157
- tooltipBox.height - options.arrowSize - options.borderRadius
158
- )}px`,
159
- });
160
- break;
161
- case "right":
162
- Object.assign(styles, {
163
- "border-color": `${options.borderColor} transparent transparent ${options.borderColor}`,
164
- "border-top-left-radius": `${options.arrowRadius}px`,
165
- left: `-${options.arrowSize / 2}px`,
166
- top: `${helpers.clamp(
167
- options.borderRadius,
168
- Math.max(anchorBox.y - position.y, 0) +
169
- Math.min(anchorBox.height, tooltipBox.height) / 2 -
170
- options.arrowSize / 2,
171
- tooltipBox.height - options.arrowSize - options.borderRadius
172
- )}px`,
173
- });
174
- break;
175
- }
176
-
177
- arrowEl.setAttribute(
178
- "style",
179
- Object.keys(styles)
180
- .map((key) => `${key}:${styles[key]}`)
181
- .join(";")
182
- );
183
- }
184
-
185
- this.getCoords = function(direction, tooltip, anchor, options) {
186
- const tooltipBox = tooltip.getBBox();
187
- const anchorBox = this.getAnchorBox(anchor);
188
- switch (direction) {
189
- case "top":
190
- return {
191
- x: helpers.clamp(
192
- options.outerOffset,
193
- anchorBox.x + anchorBox.width / 2 - tooltipBox.width / 2,
194
- this.chart.chartWidth - tooltipBox.width - options.outerOffset
195
- ),
196
- y: anchorBox.y - tooltipBox.height - options.anchorOffset,
197
- };
198
- case "bottom":
199
- return {
200
- x: helpers.clamp(
201
- options.outerOffset,
202
- anchorBox.x + anchorBox.width / 2 - tooltipBox.width / 2,
203
- this.chart.chartWidth - tooltipBox.width - options.outerOffset
204
- ),
205
- y: anchorBox.y + anchorBox.height + options.anchorOffset,
206
- };
207
- case "left":
208
- return {
209
- x: anchorBox.x - tooltipBox.width - options.anchorOffset,
210
- y: helpers.clamp(
211
- options.outerOffset,
212
- anchorBox.y + anchorBox.height / 2 - tooltipBox.height / 2,
213
- this.chart.chartHeight - tooltipBox.height - options.outerOffset
214
- ),
215
- };
216
- case "right":
217
- return {
218
- x: anchorBox.x + anchorBox.width + options.anchorOffset,
219
- y: helpers.clamp(
220
- options.outerOffset,
221
- anchorBox.y + anchorBox.height / 2 - tooltipBox.height / 2,
222
- this.chart.chartHeight - tooltipBox.height - options.outerOffset
223
- ),
224
- };
225
- }
226
- }
227
-
228
- this.getAnchorBox = function(el) {
229
- if (el.getBBox) {
230
- return el.getBBox();
231
- }
232
-
233
- const containerRect = this.chart.container.getBoundingClientRect();
234
-
235
- if (el.getBoundingClientRect) {
236
- const elRect = el.getBoundingClientRect();
237
- return {
238
- x: elRect.x - containerRect.x,
239
- y: elRect.y - containerRect.y,
240
- width: elRect.width,
241
- height: elRect.height,
242
- };
243
- }
244
- return {
245
- x: el.x - containerRect.x,
246
- y: el.y - containerRect.y,
247
- width: 0,
248
- height: 0,
249
- };
250
- }
251
-
252
- this.getPosition = function(tooltip, anchor, options) {
253
- const bbox = tooltip.getBBox();
254
-
255
- for (let direction of [options.direction, ...["top", "right", "bottom", "left"].filter((d) => d !== options.direction)]) {
256
- const coords = this.getCoords(direction, tooltip, anchor, options);
257
-
258
- if (
259
- coords.x >= 0 &&
260
- coords.x <= this.chart.chartWidth - bbox.width &&
261
- coords.y >= 0 &&
262
- coords.y <= this.chart.chartHeight - bbox.height
263
- ) {
264
- return {
265
- x: coords.x,
266
- y: coords.y,
267
- direction: direction,
268
- };
269
- }
270
- }
271
- }
272
-
273
- this.chart = chart;
274
- this.options = Object.assign({}, DR_TOOLTIP_OPTIONS_DEFAULT, options);
275
- }
276
-
277
- module.exports = { DrChartTooltip, DR_TOOLTIP_OPTIONS_DEFAULT };
@@ -1,147 +0,0 @@
1
- /**
2
- * @typedef {Object} HighChartsRenderer
3
- * @property {(rows: Rows, options: GTROptions | null, isTable: boolean, widget: any, pivotModel?: PivotModel) => string} rhPivotViewV2
4
- */
5
-
6
- /**
7
- * @typedef {Object} PivotUtilities
8
- * @property {(rows: Rows, options: GTROptions) => PivotModel} getPivotDataModel
9
- */
10
-
11
- /**
12
- * @typedef {Object} JQuery
13
- * @property {PivotUtilities} pivotUtilities
14
- */
15
-
16
- /**
17
- * @typedef {Object} PivotModel
18
- */
19
-
20
- /**
21
- * @typedef {Object} RendererOptions
22
- * @property {any} hcInstance
23
- */
24
-
25
- /**
26
- * @typedef {Object} GTROptions
27
- * @property {RendererOptions} rendererOptions
28
- */
29
-
30
- /**
31
- * @typedef {Record<string, Record<string, number | string> | number | string>[]} Rows - BE data response
32
- */
33
-
34
- export class GraphTableRenderer {
35
- /**
36
- * @type {PivotModel | undefined}
37
- */
38
- #pivotModel;
39
-
40
- /**
41
- * @type {GTROptions | null}
42
- */
43
- #options = null;
44
-
45
- /**
46
- * @type {Record<string, Record<string, number | string> | number | string>[]}
47
- *
48
- */
49
- #rows = [];
50
-
51
- /**
52
- * Utility properties
53
- */
54
- /**
55
- * @type {HighChartsRenderer}
56
- */
57
- #hcr;
58
- /**
59
- * @type {JQuery}
60
- */
61
- #$;
62
- /**
63
- * @type {PivotUtilities}
64
- */
65
- #pivotUtilities;
66
-
67
- /**
68
- * @type {any | null}
69
- */
70
- #hcInstance = null;
71
-
72
- /**
73
- *
74
- * @param {HighChartsRenderer} hcr
75
- * @param {JQuery} $
76
- */
77
- constructor(hcr, $) {
78
- this.#hcr = hcr;
79
- this.#$ = $;
80
- this.#pivotUtilities = this.#$.pivotUtilities;
81
- }
82
-
83
- /**
84
- * Creates Pivot Data Model that works we BE data response to aggregate data to render with Chart and Table
85
- * @param {Rows} rows BE data response
86
- * @param {GTROptions} options
87
- * @returns {this}
88
- */
89
- createPivotModel(rows, options) {
90
- this.#options = options;
91
- this.#rows = rows;
92
- this.#pivotModel = this.#pivotUtilities.getPivotDataModel(rows, options);
93
- return this;
94
- }
95
-
96
- /**
97
- * @returns {void}
98
- */
99
- disposePivotModel() {
100
- this.#pivotModel = undefined;
101
- }
102
-
103
- /**
104
- * @see createPivotModel
105
- * @returns {PivotModel | undefined}
106
- */
107
- getPivotModel() {
108
- return this.#pivotModel;
109
- }
110
-
111
- /**
112
- * @description returns Chart instance of HighCharts library
113
- * @returns {any | null}
114
- */
115
- hcInstance() {
116
- return this.#hcInstance;
117
- }
118
-
119
- #setHcInstance() {
120
- if (!this.#options) {
121
- return;
122
- }
123
- this.#hcInstance = this.#options.rendererOptions.hcInstance;
124
- if (!this.#hcInstance) {
125
- console.warn('[dr_renderer] HighCharts instance not found in options after the chart is rendered.');
126
- }
127
- /**
128
- * hcInstance object is not needed in options after the chart is rendered - it's an internal object of HighCharts library
129
- * Deleting to not supply it to widget object, so it cannot be used anywhere else
130
- */
131
- delete this.#options.rendererOptions.hcInstance;
132
- }
133
-
134
- renderTable(widget = null) {
135
- return this.#hcr.rhPivotViewV2(this.#rows, this.#options, true, widget, this.#pivotModel);
136
- }
137
-
138
- renderChart(widget = null) {
139
- const chart = this.#hcr.rhPivotViewV2(this.#rows, this.#options, false, widget, this.#pivotModel);
140
- setTimeout(() => {
141
- this.#setHcInstance();
142
- });
143
- return chart;
144
- }
145
- }
146
-
147
- export default GraphTableRenderer;
@@ -1,43 +0,0 @@
1
- function getSeriesPointStyles(isSelected) {
2
- return {
3
- opacity: isSelected ? 1 : 0.1,
4
- marker: {
5
- enabled: true,
6
- radius: isSelected ? 8 : 3,
7
- },
8
- dataLabels: {
9
- style: {
10
- fontWeight: isSelected ? "bold" : "normal",
11
- },
12
- },
13
- };
14
- }
15
-
16
- function setSeriesPointStylesOnClick(e) {
17
- const selectedPoint = e.point;
18
- e.point.series.chart.series.forEach((series) =>
19
- series.points.forEach((point) => {
20
- point.update(getSeriesPointStyles(point === selectedPoint), false);
21
- })
22
- );
23
- e.point.series.chart.redraw();
24
- }
25
-
26
- function setInitialPointStyles(opts, series) {
27
- series.forEach((series) => {
28
- if (Array.isArray(series.data)) {
29
- series.data.forEach((item) => {
30
- const isSelected =
31
- item && opts.selectedPoint &&
32
- item.initialName === opts.selectedPoint.initialName &&
33
- item.y.toFixed(2) === opts.selectedPoint.y.toFixed(2);
34
- item = Object.assign(item, getSeriesPointStyles(isSelected));
35
- });
36
- }
37
- });
38
- }
39
-
40
- module.exports = {
41
- setSeriesPointStylesOnClick,
42
- setInitialPointStyles,
43
- };
@@ -1,150 +0,0 @@
1
- import drRendererHelpers from '../src/dr-renderer-helpers';
2
-
3
- describe('dr-renderer-helpers', () => {
4
-
5
- describe('backendSortingKeysAreNotEmpty', () => {
6
- it('should return true if keys are not empty', () => {
7
- const keys = {
8
- row_keys: [1, 2, 3],
9
- col_keys: [1, 2, 3]
10
- };
11
- expect(drRendererHelpers.backendSortingKeysAreNotEmpty(keys)).toBe(true);
12
- });
13
-
14
- it('should return true if one of the keys is not empty', () => {
15
- const keys = {
16
- row_keys: [1, 2, 3],
17
- col_keys: []
18
- };
19
- expect(drRendererHelpers.backendSortingKeysAreNotEmpty(keys)).toBe(true);
20
- });
21
-
22
- it('should return false if keys are empty', () => {
23
- const keys = {
24
- row_keys: [],
25
- col_keys: [],
26
- };
27
- expect(drRendererHelpers.backendSortingKeysAreNotEmpty(keys)).toBe(false);
28
- });
29
-
30
- it('should return false if keys are null', () => {
31
- const keys = null;
32
- expect(drRendererHelpers.backendSortingKeysAreNotEmpty(keys)).toBe(false);
33
- });
34
- });
35
-
36
- describe('capitalize', () => {
37
- it('should capitalize a string', () => {
38
- const string = 'test';
39
- expect(drRendererHelpers.capitalize(string)).toBe('Test');
40
- });
41
-
42
- it('should not capitalize a string when it was not trimmed', () => {
43
- const string = ' test';
44
- expect(drRendererHelpers.capitalize(string)).toBe(' test');
45
- });
46
-
47
- it('should return an empty string if string is null', () => {
48
- const string = null;
49
- expect(drRendererHelpers.capitalize(string)).toBe('');
50
- });
51
- });
52
-
53
- describe('clamp', () => {
54
- it('should clamp value between teh boundaries', () => {
55
- expect(drRendererHelpers.clamp(10, 5, 20)).toBe(10);
56
- expect(drRendererHelpers.clamp(10, 25, 20)).toBe(20);
57
- expect(drRendererHelpers.clamp(10, 15, 20)).toBe(15);
58
- });
59
- });
60
-
61
- describe('isNumber', () => {
62
- it('should check whether the value is a finity number', () => {
63
- expect(drRendererHelpers.isNumber('number')).toBeFalsy();
64
- expect(drRendererHelpers.isNumber(Infinity)).toBeFalsy();
65
- expect(drRendererHelpers.isNumber(12)).toBeTruthy();
66
- });
67
- });
68
-
69
- describe('mergeDeep', () => {
70
- it('should handle the wrong data', () => {
71
- expect(drRendererHelpers.mergeDeep([1, 2, 3], { a: 1, b: 2})).toEqual([1, 2, 3]);
72
- expect(drRendererHelpers.mergeDeep('string', { a: 1, b: 2})).toEqual('string');
73
- expect(drRendererHelpers.mergeDeep({ a: 1 }, 'string')).toEqual({ a: 1 });
74
- });
75
-
76
- it('should not merge arrays and replace instead', () => {
77
- expect(drRendererHelpers.mergeDeep({
78
- a: [1, 2, 3]
79
- }, {
80
- a: [2, 3, 4]
81
- })).toEqual({
82
- a: [2, 3, 4]
83
- });
84
- });
85
-
86
- it('should merge nested objects', () => {
87
- expect(drRendererHelpers.mergeDeep({
88
- a: 1,
89
- b: {
90
- c: 3,
91
- d: 4
92
- }
93
- },
94
- {
95
- b: {
96
- d: 5,
97
- e: 6
98
- },
99
- c: 7
100
- })).toEqual({
101
- a: 1,
102
- b: {
103
- c: 3,
104
- d: 5,
105
- e: 6,
106
- },
107
- c: 7,
108
- });
109
- });
110
-
111
- it('should merge more than 2 objects', () => {
112
- expect(drRendererHelpers.mergeDeep({
113
- a: 1,
114
- b: 2
115
- },
116
- {
117
- b: 3,
118
- c: 4
119
- },
120
- {
121
- a: 5,
122
- e: 6
123
- })).toEqual({
124
- a: 5,
125
- b: 3,
126
- c: 4,
127
- e: 6
128
- });
129
- });
130
- });
131
-
132
- describe('removeSVGTextCorrection', () => {
133
- it('should remove yCorr by default', () => {
134
- const svg = {
135
- yCorr: -12
136
- };
137
- drRendererHelpers.removeSVGTextCorrection(svg);
138
- expect(svg.yCorr).toBe(0);
139
- });
140
-
141
- it('should remove yCorr by default', () => {
142
- const svg = {
143
- xCorr: -12
144
- };
145
- drRendererHelpers.removeSVGTextCorrection(svg, 'xCorr');
146
- svg.xCorr = -20;
147
- expect(svg.xCorr).toBe(0);
148
- });
149
- });
150
- });