@dhis2/analytics 25.0.0 → 25.1.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/CHANGELOG.md +7 -0
- package/build/cjs/components/DataDimension/Calculation/CalculationModal.js +2 -1
- package/build/cjs/components/DataDimension/Calculation/DataElementOption.js +1 -0
- package/build/cjs/components/DataDimension/Calculation/DataElementSelector.js +6 -3
- package/build/cjs/components/DataDimension/Calculation/FormulaField.js +2 -2
- package/build/cjs/components/DataDimension/Calculation/MathOperatorSelector.js +1 -0
- package/build/cjs/components/LegendKey/LegendKey.js +1 -1
- package/build/cjs/visualizations/config/generators/dhis/singleValue.js +112 -58
- package/build/es/components/DataDimension/Calculation/CalculationModal.js +2 -1
- package/build/es/components/DataDimension/Calculation/DataElementOption.js +1 -0
- package/build/es/components/DataDimension/Calculation/DataElementSelector.js +6 -3
- package/build/es/components/DataDimension/Calculation/FormulaField.js +2 -2
- package/build/es/components/DataDimension/Calculation/MathOperatorSelector.js +1 -0
- package/build/es/components/LegendKey/LegendKey.js +1 -1
- package/build/es/visualizations/config/generators/dhis/singleValue.js +112 -58
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# [25.1.0](https://github.com/dhis2/analytics/compare/v25.0.0...v25.1.0) (2023-04-27)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* icon in SV visualization DHIS2-10496 ([#1440](https://github.com/dhis2/analytics/issues/1440)) ([e6563ca](https://github.com/dhis2/analytics/commit/e6563cacc5e901a04d5432330b09b685936ddd70))
|
|
7
|
+
|
|
1
8
|
# [25.0.0](https://github.com/dhis2/analytics/compare/v24.10.1...v25.0.0) (2023-04-24)
|
|
2
9
|
|
|
3
10
|
|
|
@@ -415,7 +415,8 @@ const CalculationModal = _ref => {
|
|
|
415
415
|
loading: isCreatingCalculation || isUpdatingCalculation || isSavingCalculation,
|
|
416
416
|
dataTest: "save-button"
|
|
417
417
|
}, _index.default.t('Save calculation')))))), showDeletePrompt && /*#__PURE__*/_react.default.createElement(_ui.Modal, {
|
|
418
|
-
small: true
|
|
418
|
+
small: true,
|
|
419
|
+
dataTest: "calculation-delete-modal"
|
|
419
420
|
}, /*#__PURE__*/_react.default.createElement(_ui.ModalTitle, null, _index.default.t('Delete calculation')), /*#__PURE__*/_react.default.createElement(_ui.ModalContent, null, _index.default.t('Are you sure you want to delete this calculation? It may be used by other visualizations.')), /*#__PURE__*/_react.default.createElement(_ui.ModalActions, null, /*#__PURE__*/_react.default.createElement(_ui.ButtonStrip, {
|
|
420
421
|
end: true
|
|
421
422
|
}, /*#__PURE__*/_react.default.createElement(_ui.Button, {
|
|
@@ -58,6 +58,7 @@ const DataElementOption = _ref => {
|
|
|
58
58
|
className: "jsx-".concat(_DataElementOptionStyle.default.__hash) + " " + (listeners && listeners.className != null && listeners.className || attributes && attributes.className != null && attributes.className || "draggable-item")
|
|
59
59
|
}), /*#__PURE__*/_react.default.createElement("div", {
|
|
60
60
|
onDoubleClick: () => onDoubleClick(data),
|
|
61
|
+
"data-test": "data-element-option",
|
|
61
62
|
className: "jsx-".concat(_DataElementOptionStyle.default.__hash) + " " + "chip"
|
|
62
63
|
}, /*#__PURE__*/_react.default.createElement("span", {
|
|
63
64
|
className: "jsx-".concat(_DataElementOptionStyle.default.__hash) + " " + "icon"
|
|
@@ -76,11 +76,13 @@ const GroupSelector = _ref => {
|
|
|
76
76
|
}, defaultGroup ? /*#__PURE__*/_react.default.createElement(_ui.SingleSelectOption, {
|
|
77
77
|
value: defaultGroup.id,
|
|
78
78
|
key: defaultGroup.id,
|
|
79
|
-
label: defaultGroup.getName()
|
|
79
|
+
label: defaultGroup.getName(),
|
|
80
|
+
dataTest: "data-element-group-select-option-".concat(defaultGroup.id)
|
|
80
81
|
}) : null, !loading ? groups.map(group => /*#__PURE__*/_react.default.createElement(_ui.SingleSelectOption, {
|
|
81
82
|
value: group.id,
|
|
82
83
|
key: group.id,
|
|
83
|
-
label: group.name
|
|
84
|
+
label: group.name,
|
|
85
|
+
dataTest: "data-element-group-select-option-".concat(group.id)
|
|
84
86
|
})) : null), /*#__PURE__*/_react.default.createElement(_style.default, {
|
|
85
87
|
id: _DataElementSelectorStyle.default.__hash
|
|
86
88
|
}, _DataElementSelectorStyle.default));
|
|
@@ -108,7 +110,8 @@ const DisaggregationSelector = _ref2 => {
|
|
|
108
110
|
}, Object.entries(options).map(option => /*#__PURE__*/_react.default.createElement(_ui.SingleSelectOption, {
|
|
109
111
|
value: option[0],
|
|
110
112
|
key: option[0],
|
|
111
|
-
label: option[1]
|
|
113
|
+
label: option[1],
|
|
114
|
+
dataTest: "data-element-disaggregation-select-option-".concat(option[0])
|
|
112
115
|
}))), /*#__PURE__*/_react.default.createElement(_style.default, {
|
|
113
116
|
id: _DataElementSelectorStyle.default.__hash
|
|
114
117
|
}, _DataElementSelectorStyle.default));
|
|
@@ -35,7 +35,7 @@ const FORMULA_BOX_ID = 'formulabox';
|
|
|
35
35
|
exports.FORMULA_BOX_ID = FORMULA_BOX_ID;
|
|
36
36
|
|
|
37
37
|
const Placeholder = () => /*#__PURE__*/_react.default.createElement("div", {
|
|
38
|
-
"data-test":
|
|
38
|
+
"data-test": "placeholder",
|
|
39
39
|
className: "jsx-".concat(_FormulaFieldStyle.default.__hash) + " " + "placeholder"
|
|
40
40
|
}, /*#__PURE__*/_react.default.createElement(_FormulaIcon.default, null), /*#__PURE__*/_react.default.createElement("span", {
|
|
41
41
|
className: "jsx-".concat(_FormulaFieldStyle.default.__hash) + " " + "help-text"
|
|
@@ -67,7 +67,7 @@ const FormulaField = _ref => {
|
|
|
67
67
|
className: "jsx-".concat(_FormulaFieldStyle.default.__hash) + " " + "border"
|
|
68
68
|
}), /*#__PURE__*/_react.default.createElement("div", {
|
|
69
69
|
ref: setLastDropzoneRef,
|
|
70
|
-
"data-test":
|
|
70
|
+
"data-test": "formula-field",
|
|
71
71
|
className: "jsx-".concat(_FormulaFieldStyle.default.__hash) + " " + "formula-field"
|
|
72
72
|
}, loading && /*#__PURE__*/_react.default.createElement(_ui.Center, null, /*#__PURE__*/_react.default.createElement(_ui.CircularLoader, {
|
|
73
73
|
small: true
|
|
@@ -30,6 +30,7 @@ const MathOperatorSelector = _ref => {
|
|
|
30
30
|
}, /*#__PURE__*/_react.default.createElement("h4", {
|
|
31
31
|
className: "jsx-".concat(_MathOperatorSelectorStyle.default.__hash) + " " + "sub-header"
|
|
32
32
|
}, _index.default.t('Math operators')), /*#__PURE__*/_react.default.createElement("div", {
|
|
33
|
+
"data-test": "operators-list",
|
|
33
34
|
className: "jsx-".concat(_MathOperatorSelectorStyle.default.__hash) + " " + "operators"
|
|
34
35
|
}, (0, _expressions.getOperators)().map((_ref2, index) => {
|
|
35
36
|
let {
|
|
@@ -22,7 +22,7 @@ const LegendKey = _ref => {
|
|
|
22
22
|
legendSets
|
|
23
23
|
} = _ref;
|
|
24
24
|
return legendSets.length ? /*#__PURE__*/_react.default.createElement("div", {
|
|
25
|
-
"data-test":
|
|
25
|
+
"data-test": "legend-key-container",
|
|
26
26
|
className: "jsx-".concat(_LegendKeyStyle.default.__hash) + " " + "container"
|
|
27
27
|
}, legendSets.map((legendSet, index) => /*#__PURE__*/_react.default.createElement("div", {
|
|
28
28
|
key: legendSet.id,
|
|
@@ -11,62 +11,94 @@ var _fontStyle = require("../../../../modules/fontStyle.js");
|
|
|
11
11
|
|
|
12
12
|
var _legends = require("../../../../modules/legends.js");
|
|
13
13
|
|
|
14
|
-
const svgNS = 'http://www.w3.org/2000/svg';
|
|
14
|
+
const svgNS = 'http://www.w3.org/2000/svg'; // Compute text width before rendering
|
|
15
|
+
// Not exactly precise but close enough
|
|
16
|
+
|
|
17
|
+
const getTextWidth = (text, font) => {
|
|
18
|
+
const canvas = document.createElement('canvas');
|
|
19
|
+
const context = canvas.getContext('2d');
|
|
20
|
+
context.font = font;
|
|
21
|
+
return context.measureText(text).width;
|
|
22
|
+
};
|
|
15
23
|
|
|
16
24
|
const generateValueSVG = _ref => {
|
|
17
25
|
let {
|
|
18
26
|
formattedValue,
|
|
19
27
|
subText,
|
|
20
28
|
valueColor,
|
|
29
|
+
icon,
|
|
21
30
|
noData,
|
|
22
|
-
|
|
31
|
+
containerWidth,
|
|
32
|
+
containerHeight
|
|
23
33
|
} = _ref;
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
34
|
+
const ratio = containerHeight / containerWidth;
|
|
35
|
+
const iconSize = 300;
|
|
36
|
+
const iconPadding = 50;
|
|
37
|
+
const textSize = iconSize * 0.85;
|
|
38
|
+
const textWidth = getTextWidth(formattedValue, "".concat(textSize, "px Roboto"));
|
|
39
|
+
const subTextSize = 40;
|
|
40
|
+
const showIcon = icon && formattedValue !== noData.text;
|
|
41
|
+
let viewBoxWidth = textWidth;
|
|
42
|
+
|
|
43
|
+
if (showIcon) {
|
|
44
|
+
viewBoxWidth += iconSize + iconPadding;
|
|
31
45
|
}
|
|
32
46
|
|
|
47
|
+
const viewBoxHeight = viewBoxWidth * ratio;
|
|
48
|
+
const svgValue = document.createElementNS(svgNS, 'svg');
|
|
49
|
+
svgValue.setAttribute('viewBox', "0 0 ".concat(viewBoxWidth, " ").concat(viewBoxHeight));
|
|
50
|
+
svgValue.setAttribute('width', '95%');
|
|
51
|
+
svgValue.setAttribute('height', '95%');
|
|
52
|
+
svgValue.setAttribute('x', '50%');
|
|
53
|
+
svgValue.setAttribute('y', '50%');
|
|
54
|
+
svgValue.setAttribute('style', 'overflow: visible');
|
|
33
55
|
let fillColor = _ui.colors.grey900;
|
|
34
56
|
|
|
35
57
|
if (valueColor) {
|
|
36
58
|
fillColor = valueColor;
|
|
37
59
|
} else if (formattedValue === noData.text) {
|
|
38
60
|
fillColor = _ui.colors.grey600;
|
|
61
|
+
} // show icon if configured in maintenance app
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
if (showIcon) {
|
|
65
|
+
// embed icon to allow changing color
|
|
66
|
+
// (elements with fill need to use "currentColor" for this to work)
|
|
67
|
+
const iconSvgNode = document.createElementNS(svgNS, 'svg');
|
|
68
|
+
iconSvgNode.setAttribute('width', iconSize);
|
|
69
|
+
iconSvgNode.setAttribute('height', iconSize);
|
|
70
|
+
iconSvgNode.setAttribute('viewBox', '0 0 48 48');
|
|
71
|
+
iconSvgNode.setAttribute('y', "-".concat(iconSize / 2));
|
|
72
|
+
iconSvgNode.setAttribute('x', "-".concat((iconSize + iconPadding + textWidth) / 2));
|
|
73
|
+
iconSvgNode.setAttribute('style', "color: ".concat(fillColor));
|
|
74
|
+
const parser = new DOMParser();
|
|
75
|
+
const svgIconDocument = parser.parseFromString(icon, 'image/svg+xml');
|
|
76
|
+
Array.from(svgIconDocument.documentElement.children).forEach(node => iconSvgNode.appendChild(node));
|
|
77
|
+
svgValue.appendChild(iconSvgNode);
|
|
39
78
|
}
|
|
40
79
|
|
|
41
80
|
const textNode = document.createElementNS(svgNS, 'text');
|
|
42
|
-
textNode.setAttribute('text-anchor', 'middle');
|
|
43
81
|
textNode.setAttribute('font-size', textSize);
|
|
44
82
|
textNode.setAttribute('font-weight', '300');
|
|
45
83
|
textNode.setAttribute('letter-spacing', '-5');
|
|
46
|
-
textNode.setAttribute('
|
|
84
|
+
textNode.setAttribute('text-anchor', 'middle');
|
|
85
|
+
textNode.setAttribute('x', showIcon ? "".concat((iconSize + iconPadding) / 2) : 0); // vertical align, "alignment-baseline: central" is not supported by Batik
|
|
86
|
+
|
|
87
|
+
textNode.setAttribute('y', '.35em');
|
|
47
88
|
textNode.setAttribute('fill', fillColor);
|
|
48
89
|
textNode.setAttribute('data-test', 'visualization-primary-value');
|
|
49
90
|
textNode.appendChild(document.createTextNode(formattedValue));
|
|
50
91
|
svgValue.appendChild(textNode);
|
|
51
92
|
|
|
52
93
|
if (subText) {
|
|
53
|
-
const svgSubText = document.createElementNS(svgNS, 'svg');
|
|
54
|
-
const subTextSize = 40;
|
|
55
|
-
svgSubText.setAttribute('viewBox', "0 -50 ".concat(textSize * 0.75 * formattedValue.length, " ").concat(textSize + 200));
|
|
56
|
-
|
|
57
|
-
if (y) {
|
|
58
|
-
svgSubText.setAttribute('y', y);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
94
|
const subTextNode = document.createElementNS(svgNS, 'text');
|
|
62
95
|
subTextNode.setAttribute('text-anchor', 'middle');
|
|
63
96
|
subTextNode.setAttribute('font-size', subTextSize);
|
|
64
|
-
subTextNode.setAttribute('
|
|
65
|
-
subTextNode.setAttribute('
|
|
97
|
+
subTextNode.setAttribute('y', iconSize / 2);
|
|
98
|
+
subTextNode.setAttribute('dy', subTextSize);
|
|
66
99
|
subTextNode.setAttribute('fill', _ui.colors.grey600);
|
|
67
100
|
subTextNode.appendChild(document.createTextNode(subText));
|
|
68
|
-
|
|
69
|
-
svgValue.appendChild(svgSubText);
|
|
101
|
+
svgValue.appendChild(subTextNode);
|
|
70
102
|
}
|
|
71
103
|
|
|
72
104
|
return svgValue;
|
|
@@ -74,14 +106,27 @@ const generateValueSVG = _ref => {
|
|
|
74
106
|
|
|
75
107
|
const generateDashboardItem = (config, _ref2) => {
|
|
76
108
|
let {
|
|
109
|
+
svgContainer,
|
|
110
|
+
width,
|
|
111
|
+
height,
|
|
77
112
|
valueColor,
|
|
78
113
|
titleColor,
|
|
79
114
|
backgroundColor,
|
|
80
|
-
noData
|
|
115
|
+
noData,
|
|
116
|
+
icon
|
|
81
117
|
} = _ref2;
|
|
118
|
+
svgContainer.appendChild(generateValueSVG({
|
|
119
|
+
formattedValue: config.formattedValue,
|
|
120
|
+
subText: config.subText,
|
|
121
|
+
valueColor,
|
|
122
|
+
noData,
|
|
123
|
+
icon,
|
|
124
|
+
containerWidth: width,
|
|
125
|
+
containerHeight: height
|
|
126
|
+
}));
|
|
82
127
|
const container = document.createElement('div');
|
|
83
128
|
container.setAttribute('style', "display: flex; flex-direction: column; align-items: center; justify-content: center; width: 100%; height: 100%; background-color:".concat(backgroundColor, ";"));
|
|
84
|
-
const titleStyle = "font-size: 12px; color: ".concat(titleColor || '#666', ";");
|
|
129
|
+
const titleStyle = "padding: 0 8px; text-align: center; font-size: 12px; color: ".concat(titleColor || '#666', ";");
|
|
85
130
|
const title = document.createElement('span');
|
|
86
131
|
title.setAttribute('style', titleStyle);
|
|
87
132
|
|
|
@@ -92,18 +137,12 @@ const generateDashboardItem = (config, _ref2) => {
|
|
|
92
137
|
|
|
93
138
|
if (config.subtitle) {
|
|
94
139
|
const subtitle = document.createElement('span');
|
|
95
|
-
subtitle.setAttribute('style', titleStyle + ' margin-top: 4px;
|
|
140
|
+
subtitle.setAttribute('style', titleStyle + ' margin-top: 4px;');
|
|
96
141
|
subtitle.appendChild(document.createTextNode(config.subtitle));
|
|
97
142
|
container.appendChild(subtitle);
|
|
98
143
|
}
|
|
99
144
|
|
|
100
|
-
container.appendChild(
|
|
101
|
-
formattedValue: config.formattedValue,
|
|
102
|
-
subText: config.subText,
|
|
103
|
-
valueColor,
|
|
104
|
-
noData,
|
|
105
|
-
y: 40
|
|
106
|
-
}));
|
|
145
|
+
container.appendChild(svgContainer);
|
|
107
146
|
return container;
|
|
108
147
|
};
|
|
109
148
|
|
|
@@ -137,33 +176,27 @@ const getXFromTextAlign = textAlign => {
|
|
|
137
176
|
|
|
138
177
|
const generateDVItem = (config, _ref3) => {
|
|
139
178
|
let {
|
|
179
|
+
svgContainer,
|
|
180
|
+
width,
|
|
181
|
+
height,
|
|
140
182
|
valueColor,
|
|
183
|
+
noData,
|
|
141
184
|
backgroundColor,
|
|
142
185
|
titleColor,
|
|
143
|
-
parentEl,
|
|
144
186
|
fontStyle,
|
|
145
|
-
|
|
187
|
+
icon
|
|
146
188
|
} = _ref3;
|
|
147
|
-
const parentElBBox = parentEl.getBoundingClientRect();
|
|
148
|
-
const width = parentElBBox.width;
|
|
149
|
-
const height = parentElBBox.height;
|
|
150
|
-
const svgNS = 'http://www.w3.org/2000/svg';
|
|
151
|
-
const svg = document.createElementNS(svgNS, 'svg');
|
|
152
|
-
svg.setAttribute('xmlns', svgNS);
|
|
153
|
-
svg.setAttribute('viewBox', "0 0 ".concat(width, " ").concat(height));
|
|
154
|
-
svg.setAttribute('width', width);
|
|
155
|
-
svg.setAttribute('height', height);
|
|
156
|
-
svg.setAttribute('data-test', 'visualization-container');
|
|
157
189
|
|
|
158
190
|
if (backgroundColor) {
|
|
159
|
-
|
|
191
|
+
svgContainer.setAttribute('style', "background-color: ".concat(backgroundColor, ";"));
|
|
160
192
|
const background = document.createElementNS(svgNS, 'rect');
|
|
161
193
|
background.setAttribute('width', '100%');
|
|
162
194
|
background.setAttribute('height', '100%');
|
|
163
195
|
background.setAttribute('fill', backgroundColor);
|
|
164
|
-
|
|
196
|
+
svgContainer.appendChild(background);
|
|
165
197
|
}
|
|
166
198
|
|
|
199
|
+
const svgWrapper = document.createElementNS(svgNS, 'svg');
|
|
167
200
|
const title = document.createElementNS(svgNS, 'text');
|
|
168
201
|
const titleFontStyle = (0, _fontStyle.mergeFontStyleWithDefault)(fontStyle && fontStyle[_fontStyle.FONT_STYLE_VISUALIZATION_TITLE], _fontStyle.FONT_STYLE_VISUALIZATION_TITLE);
|
|
169
202
|
title.setAttribute('x', getXFromTextAlign(titleFontStyle[_fontStyle.FONT_STYLE_OPTION_TEXT_ALIGN]));
|
|
@@ -183,7 +216,7 @@ const generateDVItem = (config, _ref3) => {
|
|
|
183
216
|
|
|
184
217
|
if (config.title) {
|
|
185
218
|
title.appendChild(document.createTextNode(config.title));
|
|
186
|
-
|
|
219
|
+
svgWrapper.appendChild(title);
|
|
187
220
|
}
|
|
188
221
|
|
|
189
222
|
const subtitleFontStyle = (0, _fontStyle.mergeFontStyleWithDefault)(fontStyle && fontStyle[_fontStyle.FONT_STYLE_VISUALIZATION_SUBTITLE], _fontStyle.FONT_STYLE_VISUALIZATION_SUBTITLE);
|
|
@@ -206,20 +239,24 @@ const generateDVItem = (config, _ref3) => {
|
|
|
206
239
|
|
|
207
240
|
if (config.subtitle) {
|
|
208
241
|
subtitle.appendChild(document.createTextNode(config.subtitle));
|
|
209
|
-
|
|
242
|
+
svgWrapper.appendChild(subtitle);
|
|
210
243
|
}
|
|
211
244
|
|
|
212
|
-
|
|
245
|
+
svgContainer.appendChild(svgWrapper);
|
|
246
|
+
svgContainer.appendChild(generateValueSVG({
|
|
213
247
|
formattedValue: config.formattedValue,
|
|
214
248
|
subText: config.subText,
|
|
215
249
|
valueColor,
|
|
216
250
|
noData,
|
|
217
|
-
|
|
251
|
+
icon,
|
|
252
|
+
containerWidth: width,
|
|
253
|
+
containerHeight: height
|
|
218
254
|
}));
|
|
219
|
-
return
|
|
255
|
+
return svgContainer;
|
|
220
256
|
};
|
|
221
257
|
|
|
222
|
-
const shouldUseContrastColor =
|
|
258
|
+
const shouldUseContrastColor = function () {
|
|
259
|
+
let inputColor = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
|
|
223
260
|
// based on https://stackoverflow.com/questions/3942878/how-to-decide-font-color-in-white-or-black-depending-on-background-color
|
|
224
261
|
var color = inputColor.charAt(0) === '#' ? inputColor.substring(1, 7) : inputColor;
|
|
225
262
|
var r = parseInt(color.substring(0, 2), 16); // hexToR
|
|
@@ -246,7 +283,8 @@ function _default(config, parentEl, _ref4) {
|
|
|
246
283
|
legendSets,
|
|
247
284
|
fontStyle,
|
|
248
285
|
noData,
|
|
249
|
-
legendOptions
|
|
286
|
+
legendOptions,
|
|
287
|
+
icon
|
|
250
288
|
} = _ref4;
|
|
251
289
|
const legendSet = legendOptions && legendSets[0];
|
|
252
290
|
const legendColor = legendSet && (0, _legends.getColorByValueFromLegendSet)(legendSet, config.value);
|
|
@@ -264,26 +302,42 @@ function _default(config, parentEl, _ref4) {
|
|
|
264
302
|
parentEl.style.overflow = 'hidden';
|
|
265
303
|
parentEl.style.display = 'flex';
|
|
266
304
|
parentEl.style.justifyContent = 'center';
|
|
305
|
+
const parentElBBox = parentEl.getBoundingClientRect();
|
|
306
|
+
const width = parentElBBox.width;
|
|
307
|
+
const height = parentElBBox.height;
|
|
308
|
+
const svgContainer = document.createElementNS(svgNS, 'svg');
|
|
309
|
+
svgContainer.setAttribute('xmlns', svgNS);
|
|
310
|
+
svgContainer.setAttribute('viewBox', "0 0 ".concat(width, " ").concat(height));
|
|
311
|
+
svgContainer.setAttribute('width', dashboard ? '100%' : width);
|
|
312
|
+
svgContainer.setAttribute('height', dashboard ? '100%' : height);
|
|
313
|
+
svgContainer.setAttribute('data-test', 'visualization-container');
|
|
267
314
|
|
|
268
315
|
if (dashboard) {
|
|
269
316
|
parentEl.style.borderRadius = _ui.spacers.dp8;
|
|
270
317
|
return generateDashboardItem(config, {
|
|
318
|
+
svgContainer,
|
|
319
|
+
width,
|
|
320
|
+
height,
|
|
271
321
|
valueColor,
|
|
272
322
|
backgroundColor,
|
|
273
323
|
noData,
|
|
274
|
-
|
|
324
|
+
icon,
|
|
325
|
+
...(legendColor && shouldUseContrastColor(legendColor) ? {
|
|
275
326
|
titleColor: _ui.colors.white
|
|
276
327
|
} : {})
|
|
277
328
|
});
|
|
278
329
|
} else {
|
|
279
330
|
parentEl.style.height = "100%";
|
|
280
331
|
return generateDVItem(config, {
|
|
332
|
+
svgContainer,
|
|
333
|
+
width,
|
|
334
|
+
height,
|
|
281
335
|
valueColor,
|
|
282
336
|
backgroundColor,
|
|
283
337
|
titleColor,
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
338
|
+
noData,
|
|
339
|
+
icon,
|
|
340
|
+
fontStyle
|
|
287
341
|
});
|
|
288
342
|
}
|
|
289
343
|
}
|
|
@@ -387,7 +387,8 @@ const CalculationModal = _ref => {
|
|
|
387
387
|
loading: isCreatingCalculation || isUpdatingCalculation || isSavingCalculation,
|
|
388
388
|
dataTest: "save-button"
|
|
389
389
|
}, i18n.t('Save calculation')))))), showDeletePrompt && /*#__PURE__*/React.createElement(Modal, {
|
|
390
|
-
small: true
|
|
390
|
+
small: true,
|
|
391
|
+
dataTest: "calculation-delete-modal"
|
|
391
392
|
}, /*#__PURE__*/React.createElement(ModalTitle, null, i18n.t('Delete calculation')), /*#__PURE__*/React.createElement(ModalContent, null, i18n.t('Are you sure you want to delete this calculation? It may be used by other visualizations.')), /*#__PURE__*/React.createElement(ModalActions, null, /*#__PURE__*/React.createElement(ButtonStrip, {
|
|
392
393
|
end: true
|
|
393
394
|
}, /*#__PURE__*/React.createElement(Button, {
|
|
@@ -42,6 +42,7 @@ const DataElementOption = _ref => {
|
|
|
42
42
|
className: "jsx-".concat(styles.__hash) + " " + (listeners && listeners.className != null && listeners.className || attributes && attributes.className != null && attributes.className || "draggable-item")
|
|
43
43
|
}), /*#__PURE__*/React.createElement("div", {
|
|
44
44
|
onDoubleClick: () => onDoubleClick(data),
|
|
45
|
+
"data-test": "data-element-option",
|
|
45
46
|
className: "jsx-".concat(styles.__hash) + " " + "chip"
|
|
46
47
|
}, /*#__PURE__*/React.createElement("span", {
|
|
47
48
|
className: "jsx-".concat(styles.__hash) + " " + "icon"
|
|
@@ -51,11 +51,13 @@ const GroupSelector = _ref => {
|
|
|
51
51
|
}, defaultGroup ? /*#__PURE__*/React.createElement(SingleSelectOption, {
|
|
52
52
|
value: defaultGroup.id,
|
|
53
53
|
key: defaultGroup.id,
|
|
54
|
-
label: defaultGroup.getName()
|
|
54
|
+
label: defaultGroup.getName(),
|
|
55
|
+
dataTest: "data-element-group-select-option-".concat(defaultGroup.id)
|
|
55
56
|
}) : null, !loading ? groups.map(group => /*#__PURE__*/React.createElement(SingleSelectOption, {
|
|
56
57
|
value: group.id,
|
|
57
58
|
key: group.id,
|
|
58
|
-
label: group.name
|
|
59
|
+
label: group.name,
|
|
60
|
+
dataTest: "data-element-group-select-option-".concat(group.id)
|
|
59
61
|
})) : null), /*#__PURE__*/React.createElement(_JSXStyle, {
|
|
60
62
|
id: styles.__hash
|
|
61
63
|
}, styles));
|
|
@@ -83,7 +85,8 @@ const DisaggregationSelector = _ref2 => {
|
|
|
83
85
|
}, Object.entries(options).map(option => /*#__PURE__*/React.createElement(SingleSelectOption, {
|
|
84
86
|
value: option[0],
|
|
85
87
|
key: option[0],
|
|
86
|
-
label: option[1]
|
|
88
|
+
label: option[1],
|
|
89
|
+
dataTest: "data-element-disaggregation-select-option-".concat(option[0])
|
|
87
90
|
}))), /*#__PURE__*/React.createElement(_JSXStyle, {
|
|
88
91
|
id: styles.__hash
|
|
89
92
|
}, styles));
|
|
@@ -13,7 +13,7 @@ export const LAST_DROPZONE_ID = 'lastdropzone';
|
|
|
13
13
|
export const FORMULA_BOX_ID = 'formulabox';
|
|
14
14
|
|
|
15
15
|
const Placeholder = () => /*#__PURE__*/React.createElement("div", {
|
|
16
|
-
"data-test":
|
|
16
|
+
"data-test": "placeholder",
|
|
17
17
|
className: "jsx-".concat(styles.__hash) + " " + "placeholder"
|
|
18
18
|
}, /*#__PURE__*/React.createElement(FormulaIcon, null), /*#__PURE__*/React.createElement("span", {
|
|
19
19
|
className: "jsx-".concat(styles.__hash) + " " + "help-text"
|
|
@@ -45,7 +45,7 @@ const FormulaField = _ref => {
|
|
|
45
45
|
className: "jsx-".concat(styles.__hash) + " " + "border"
|
|
46
46
|
}), /*#__PURE__*/React.createElement("div", {
|
|
47
47
|
ref: setLastDropzoneRef,
|
|
48
|
-
"data-test":
|
|
48
|
+
"data-test": "formula-field",
|
|
49
49
|
className: "jsx-".concat(styles.__hash) + " " + "formula-field"
|
|
50
50
|
}, loading && /*#__PURE__*/React.createElement(Center, null, /*#__PURE__*/React.createElement(CircularLoader, {
|
|
51
51
|
small: true
|
|
@@ -15,6 +15,7 @@ const MathOperatorSelector = _ref => {
|
|
|
15
15
|
}, /*#__PURE__*/React.createElement("h4", {
|
|
16
16
|
className: "jsx-".concat(styles.__hash) + " " + "sub-header"
|
|
17
17
|
}, i18n.t('Math operators')), /*#__PURE__*/React.createElement("div", {
|
|
18
|
+
"data-test": "operators-list",
|
|
18
19
|
className: "jsx-".concat(styles.__hash) + " " + "operators"
|
|
19
20
|
}, getOperators().map((_ref2, index) => {
|
|
20
21
|
let {
|
|
@@ -9,7 +9,7 @@ const LegendKey = _ref => {
|
|
|
9
9
|
legendSets
|
|
10
10
|
} = _ref;
|
|
11
11
|
return legendSets.length ? /*#__PURE__*/React.createElement("div", {
|
|
12
|
-
"data-test":
|
|
12
|
+
"data-test": "legend-key-container",
|
|
13
13
|
className: "jsx-".concat(styles.__hash) + " " + "container"
|
|
14
14
|
}, legendSets.map((legendSet, index) => /*#__PURE__*/React.createElement("div", {
|
|
15
15
|
key: legendSet.id,
|
|
@@ -1,62 +1,94 @@
|
|
|
1
1
|
import { colors, spacers } from '@dhis2/ui';
|
|
2
2
|
import { FONT_STYLE_VISUALIZATION_TITLE, FONT_STYLE_VISUALIZATION_SUBTITLE, FONT_STYLE_OPTION_FONT_SIZE, FONT_STYLE_OPTION_TEXT_COLOR, FONT_STYLE_OPTION_TEXT_ALIGN, FONT_STYLE_OPTION_ITALIC, FONT_STYLE_OPTION_BOLD, TEXT_ALIGN_LEFT, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER, mergeFontStyleWithDefault, defaultFontStyle } from '../../../../modules/fontStyle.js';
|
|
3
3
|
import { getColorByValueFromLegendSet, LEGEND_DISPLAY_STYLE_FILL } from '../../../../modules/legends.js';
|
|
4
|
-
const svgNS = 'http://www.w3.org/2000/svg';
|
|
4
|
+
const svgNS = 'http://www.w3.org/2000/svg'; // Compute text width before rendering
|
|
5
|
+
// Not exactly precise but close enough
|
|
6
|
+
|
|
7
|
+
const getTextWidth = (text, font) => {
|
|
8
|
+
const canvas = document.createElement('canvas');
|
|
9
|
+
const context = canvas.getContext('2d');
|
|
10
|
+
context.font = font;
|
|
11
|
+
return context.measureText(text).width;
|
|
12
|
+
};
|
|
5
13
|
|
|
6
14
|
const generateValueSVG = _ref => {
|
|
7
15
|
let {
|
|
8
16
|
formattedValue,
|
|
9
17
|
subText,
|
|
10
18
|
valueColor,
|
|
19
|
+
icon,
|
|
11
20
|
noData,
|
|
12
|
-
|
|
21
|
+
containerWidth,
|
|
22
|
+
containerHeight
|
|
13
23
|
} = _ref;
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
24
|
+
const ratio = containerHeight / containerWidth;
|
|
25
|
+
const iconSize = 300;
|
|
26
|
+
const iconPadding = 50;
|
|
27
|
+
const textSize = iconSize * 0.85;
|
|
28
|
+
const textWidth = getTextWidth(formattedValue, "".concat(textSize, "px Roboto"));
|
|
29
|
+
const subTextSize = 40;
|
|
30
|
+
const showIcon = icon && formattedValue !== noData.text;
|
|
31
|
+
let viewBoxWidth = textWidth;
|
|
32
|
+
|
|
33
|
+
if (showIcon) {
|
|
34
|
+
viewBoxWidth += iconSize + iconPadding;
|
|
21
35
|
}
|
|
22
36
|
|
|
37
|
+
const viewBoxHeight = viewBoxWidth * ratio;
|
|
38
|
+
const svgValue = document.createElementNS(svgNS, 'svg');
|
|
39
|
+
svgValue.setAttribute('viewBox', "0 0 ".concat(viewBoxWidth, " ").concat(viewBoxHeight));
|
|
40
|
+
svgValue.setAttribute('width', '95%');
|
|
41
|
+
svgValue.setAttribute('height', '95%');
|
|
42
|
+
svgValue.setAttribute('x', '50%');
|
|
43
|
+
svgValue.setAttribute('y', '50%');
|
|
44
|
+
svgValue.setAttribute('style', 'overflow: visible');
|
|
23
45
|
let fillColor = colors.grey900;
|
|
24
46
|
|
|
25
47
|
if (valueColor) {
|
|
26
48
|
fillColor = valueColor;
|
|
27
49
|
} else if (formattedValue === noData.text) {
|
|
28
50
|
fillColor = colors.grey600;
|
|
51
|
+
} // show icon if configured in maintenance app
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
if (showIcon) {
|
|
55
|
+
// embed icon to allow changing color
|
|
56
|
+
// (elements with fill need to use "currentColor" for this to work)
|
|
57
|
+
const iconSvgNode = document.createElementNS(svgNS, 'svg');
|
|
58
|
+
iconSvgNode.setAttribute('width', iconSize);
|
|
59
|
+
iconSvgNode.setAttribute('height', iconSize);
|
|
60
|
+
iconSvgNode.setAttribute('viewBox', '0 0 48 48');
|
|
61
|
+
iconSvgNode.setAttribute('y', "-".concat(iconSize / 2));
|
|
62
|
+
iconSvgNode.setAttribute('x', "-".concat((iconSize + iconPadding + textWidth) / 2));
|
|
63
|
+
iconSvgNode.setAttribute('style', "color: ".concat(fillColor));
|
|
64
|
+
const parser = new DOMParser();
|
|
65
|
+
const svgIconDocument = parser.parseFromString(icon, 'image/svg+xml');
|
|
66
|
+
Array.from(svgIconDocument.documentElement.children).forEach(node => iconSvgNode.appendChild(node));
|
|
67
|
+
svgValue.appendChild(iconSvgNode);
|
|
29
68
|
}
|
|
30
69
|
|
|
31
70
|
const textNode = document.createElementNS(svgNS, 'text');
|
|
32
|
-
textNode.setAttribute('text-anchor', 'middle');
|
|
33
71
|
textNode.setAttribute('font-size', textSize);
|
|
34
72
|
textNode.setAttribute('font-weight', '300');
|
|
35
73
|
textNode.setAttribute('letter-spacing', '-5');
|
|
36
|
-
textNode.setAttribute('
|
|
74
|
+
textNode.setAttribute('text-anchor', 'middle');
|
|
75
|
+
textNode.setAttribute('x', showIcon ? "".concat((iconSize + iconPadding) / 2) : 0); // vertical align, "alignment-baseline: central" is not supported by Batik
|
|
76
|
+
|
|
77
|
+
textNode.setAttribute('y', '.35em');
|
|
37
78
|
textNode.setAttribute('fill', fillColor);
|
|
38
79
|
textNode.setAttribute('data-test', 'visualization-primary-value');
|
|
39
80
|
textNode.appendChild(document.createTextNode(formattedValue));
|
|
40
81
|
svgValue.appendChild(textNode);
|
|
41
82
|
|
|
42
83
|
if (subText) {
|
|
43
|
-
const svgSubText = document.createElementNS(svgNS, 'svg');
|
|
44
|
-
const subTextSize = 40;
|
|
45
|
-
svgSubText.setAttribute('viewBox', "0 -50 ".concat(textSize * 0.75 * formattedValue.length, " ").concat(textSize + 200));
|
|
46
|
-
|
|
47
|
-
if (y) {
|
|
48
|
-
svgSubText.setAttribute('y', y);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
84
|
const subTextNode = document.createElementNS(svgNS, 'text');
|
|
52
85
|
subTextNode.setAttribute('text-anchor', 'middle');
|
|
53
86
|
subTextNode.setAttribute('font-size', subTextSize);
|
|
54
|
-
subTextNode.setAttribute('
|
|
55
|
-
subTextNode.setAttribute('
|
|
87
|
+
subTextNode.setAttribute('y', iconSize / 2);
|
|
88
|
+
subTextNode.setAttribute('dy', subTextSize);
|
|
56
89
|
subTextNode.setAttribute('fill', colors.grey600);
|
|
57
90
|
subTextNode.appendChild(document.createTextNode(subText));
|
|
58
|
-
|
|
59
|
-
svgValue.appendChild(svgSubText);
|
|
91
|
+
svgValue.appendChild(subTextNode);
|
|
60
92
|
}
|
|
61
93
|
|
|
62
94
|
return svgValue;
|
|
@@ -64,14 +96,27 @@ const generateValueSVG = _ref => {
|
|
|
64
96
|
|
|
65
97
|
const generateDashboardItem = (config, _ref2) => {
|
|
66
98
|
let {
|
|
99
|
+
svgContainer,
|
|
100
|
+
width,
|
|
101
|
+
height,
|
|
67
102
|
valueColor,
|
|
68
103
|
titleColor,
|
|
69
104
|
backgroundColor,
|
|
70
|
-
noData
|
|
105
|
+
noData,
|
|
106
|
+
icon
|
|
71
107
|
} = _ref2;
|
|
108
|
+
svgContainer.appendChild(generateValueSVG({
|
|
109
|
+
formattedValue: config.formattedValue,
|
|
110
|
+
subText: config.subText,
|
|
111
|
+
valueColor,
|
|
112
|
+
noData,
|
|
113
|
+
icon,
|
|
114
|
+
containerWidth: width,
|
|
115
|
+
containerHeight: height
|
|
116
|
+
}));
|
|
72
117
|
const container = document.createElement('div');
|
|
73
118
|
container.setAttribute('style', "display: flex; flex-direction: column; align-items: center; justify-content: center; width: 100%; height: 100%; background-color:".concat(backgroundColor, ";"));
|
|
74
|
-
const titleStyle = "font-size: 12px; color: ".concat(titleColor || '#666', ";");
|
|
119
|
+
const titleStyle = "padding: 0 8px; text-align: center; font-size: 12px; color: ".concat(titleColor || '#666', ";");
|
|
75
120
|
const title = document.createElement('span');
|
|
76
121
|
title.setAttribute('style', titleStyle);
|
|
77
122
|
|
|
@@ -82,18 +127,12 @@ const generateDashboardItem = (config, _ref2) => {
|
|
|
82
127
|
|
|
83
128
|
if (config.subtitle) {
|
|
84
129
|
const subtitle = document.createElement('span');
|
|
85
|
-
subtitle.setAttribute('style', titleStyle + ' margin-top: 4px;
|
|
130
|
+
subtitle.setAttribute('style', titleStyle + ' margin-top: 4px;');
|
|
86
131
|
subtitle.appendChild(document.createTextNode(config.subtitle));
|
|
87
132
|
container.appendChild(subtitle);
|
|
88
133
|
}
|
|
89
134
|
|
|
90
|
-
container.appendChild(
|
|
91
|
-
formattedValue: config.formattedValue,
|
|
92
|
-
subText: config.subText,
|
|
93
|
-
valueColor,
|
|
94
|
-
noData,
|
|
95
|
-
y: 40
|
|
96
|
-
}));
|
|
135
|
+
container.appendChild(svgContainer);
|
|
97
136
|
return container;
|
|
98
137
|
};
|
|
99
138
|
|
|
@@ -127,33 +166,27 @@ const getXFromTextAlign = textAlign => {
|
|
|
127
166
|
|
|
128
167
|
const generateDVItem = (config, _ref3) => {
|
|
129
168
|
let {
|
|
169
|
+
svgContainer,
|
|
170
|
+
width,
|
|
171
|
+
height,
|
|
130
172
|
valueColor,
|
|
173
|
+
noData,
|
|
131
174
|
backgroundColor,
|
|
132
175
|
titleColor,
|
|
133
|
-
parentEl,
|
|
134
176
|
fontStyle,
|
|
135
|
-
|
|
177
|
+
icon
|
|
136
178
|
} = _ref3;
|
|
137
|
-
const parentElBBox = parentEl.getBoundingClientRect();
|
|
138
|
-
const width = parentElBBox.width;
|
|
139
|
-
const height = parentElBBox.height;
|
|
140
|
-
const svgNS = 'http://www.w3.org/2000/svg';
|
|
141
|
-
const svg = document.createElementNS(svgNS, 'svg');
|
|
142
|
-
svg.setAttribute('xmlns', svgNS);
|
|
143
|
-
svg.setAttribute('viewBox', "0 0 ".concat(width, " ").concat(height));
|
|
144
|
-
svg.setAttribute('width', width);
|
|
145
|
-
svg.setAttribute('height', height);
|
|
146
|
-
svg.setAttribute('data-test', 'visualization-container');
|
|
147
179
|
|
|
148
180
|
if (backgroundColor) {
|
|
149
|
-
|
|
181
|
+
svgContainer.setAttribute('style', "background-color: ".concat(backgroundColor, ";"));
|
|
150
182
|
const background = document.createElementNS(svgNS, 'rect');
|
|
151
183
|
background.setAttribute('width', '100%');
|
|
152
184
|
background.setAttribute('height', '100%');
|
|
153
185
|
background.setAttribute('fill', backgroundColor);
|
|
154
|
-
|
|
186
|
+
svgContainer.appendChild(background);
|
|
155
187
|
}
|
|
156
188
|
|
|
189
|
+
const svgWrapper = document.createElementNS(svgNS, 'svg');
|
|
157
190
|
const title = document.createElementNS(svgNS, 'text');
|
|
158
191
|
const titleFontStyle = mergeFontStyleWithDefault(fontStyle && fontStyle[FONT_STYLE_VISUALIZATION_TITLE], FONT_STYLE_VISUALIZATION_TITLE);
|
|
159
192
|
title.setAttribute('x', getXFromTextAlign(titleFontStyle[FONT_STYLE_OPTION_TEXT_ALIGN]));
|
|
@@ -173,7 +206,7 @@ const generateDVItem = (config, _ref3) => {
|
|
|
173
206
|
|
|
174
207
|
if (config.title) {
|
|
175
208
|
title.appendChild(document.createTextNode(config.title));
|
|
176
|
-
|
|
209
|
+
svgWrapper.appendChild(title);
|
|
177
210
|
}
|
|
178
211
|
|
|
179
212
|
const subtitleFontStyle = mergeFontStyleWithDefault(fontStyle && fontStyle[FONT_STYLE_VISUALIZATION_SUBTITLE], FONT_STYLE_VISUALIZATION_SUBTITLE);
|
|
@@ -196,20 +229,24 @@ const generateDVItem = (config, _ref3) => {
|
|
|
196
229
|
|
|
197
230
|
if (config.subtitle) {
|
|
198
231
|
subtitle.appendChild(document.createTextNode(config.subtitle));
|
|
199
|
-
|
|
232
|
+
svgWrapper.appendChild(subtitle);
|
|
200
233
|
}
|
|
201
234
|
|
|
202
|
-
|
|
235
|
+
svgContainer.appendChild(svgWrapper);
|
|
236
|
+
svgContainer.appendChild(generateValueSVG({
|
|
203
237
|
formattedValue: config.formattedValue,
|
|
204
238
|
subText: config.subText,
|
|
205
239
|
valueColor,
|
|
206
240
|
noData,
|
|
207
|
-
|
|
241
|
+
icon,
|
|
242
|
+
containerWidth: width,
|
|
243
|
+
containerHeight: height
|
|
208
244
|
}));
|
|
209
|
-
return
|
|
245
|
+
return svgContainer;
|
|
210
246
|
};
|
|
211
247
|
|
|
212
|
-
const shouldUseContrastColor =
|
|
248
|
+
const shouldUseContrastColor = function () {
|
|
249
|
+
let inputColor = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
|
|
213
250
|
// based on https://stackoverflow.com/questions/3942878/how-to-decide-font-color-in-white-or-black-depending-on-background-color
|
|
214
251
|
var color = inputColor.charAt(0) === '#' ? inputColor.substring(1, 7) : inputColor;
|
|
215
252
|
var r = parseInt(color.substring(0, 2), 16); // hexToR
|
|
@@ -236,7 +273,8 @@ export default function (config, parentEl, _ref4) {
|
|
|
236
273
|
legendSets,
|
|
237
274
|
fontStyle,
|
|
238
275
|
noData,
|
|
239
|
-
legendOptions
|
|
276
|
+
legendOptions,
|
|
277
|
+
icon
|
|
240
278
|
} = _ref4;
|
|
241
279
|
const legendSet = legendOptions && legendSets[0];
|
|
242
280
|
const legendColor = legendSet && getColorByValueFromLegendSet(legendSet, config.value);
|
|
@@ -254,26 +292,42 @@ export default function (config, parentEl, _ref4) {
|
|
|
254
292
|
parentEl.style.overflow = 'hidden';
|
|
255
293
|
parentEl.style.display = 'flex';
|
|
256
294
|
parentEl.style.justifyContent = 'center';
|
|
295
|
+
const parentElBBox = parentEl.getBoundingClientRect();
|
|
296
|
+
const width = parentElBBox.width;
|
|
297
|
+
const height = parentElBBox.height;
|
|
298
|
+
const svgContainer = document.createElementNS(svgNS, 'svg');
|
|
299
|
+
svgContainer.setAttribute('xmlns', svgNS);
|
|
300
|
+
svgContainer.setAttribute('viewBox', "0 0 ".concat(width, " ").concat(height));
|
|
301
|
+
svgContainer.setAttribute('width', dashboard ? '100%' : width);
|
|
302
|
+
svgContainer.setAttribute('height', dashboard ? '100%' : height);
|
|
303
|
+
svgContainer.setAttribute('data-test', 'visualization-container');
|
|
257
304
|
|
|
258
305
|
if (dashboard) {
|
|
259
306
|
parentEl.style.borderRadius = spacers.dp8;
|
|
260
307
|
return generateDashboardItem(config, {
|
|
308
|
+
svgContainer,
|
|
309
|
+
width,
|
|
310
|
+
height,
|
|
261
311
|
valueColor,
|
|
262
312
|
backgroundColor,
|
|
263
313
|
noData,
|
|
264
|
-
|
|
314
|
+
icon,
|
|
315
|
+
...(legendColor && shouldUseContrastColor(legendColor) ? {
|
|
265
316
|
titleColor: colors.white
|
|
266
317
|
} : {})
|
|
267
318
|
});
|
|
268
319
|
} else {
|
|
269
320
|
parentEl.style.height = "100%";
|
|
270
321
|
return generateDVItem(config, {
|
|
322
|
+
svgContainer,
|
|
323
|
+
width,
|
|
324
|
+
height,
|
|
271
325
|
valueColor,
|
|
272
326
|
backgroundColor,
|
|
273
327
|
titleColor,
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
328
|
+
noData,
|
|
329
|
+
icon,
|
|
330
|
+
fontStyle
|
|
277
331
|
});
|
|
278
332
|
}
|
|
279
333
|
}
|