@eturnity/eturnity_reusable_components 8.19.8-EPDM-14690.1 → 8.19.8-EPDM-11600.10
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/package.json +1 -1
- package/src/assets/svgIcons/erase.svg +2 -3
- package/src/assets/theme.js +1 -1
- package/src/components/barchart/BottomFields.vue +37 -125
- package/src/components/barchart/composables/useAxisCalculations.js +1 -1
- package/src/components/barchart/composables/useChartData.js +1 -1
- package/src/components/barchart/composables/useTooltip.js +3 -28
- package/src/components/barchart/index.vue +16 -54
- package/src/components/barchart/styles/bottomFields.js +4 -18
- package/src/components/barchart/styles/chart.js +12 -15
- package/src/components/errorMessage/index.vue +1 -1
- package/src/components/infoCard/index.vue +3 -15
- package/src/components/infoCard/infoCard.spec.js +3 -3
- package/src/components/infoText/index.vue +31 -36
- package/src/components/inputs/inputNumber/InputNumber.stories.js +5 -5
- package/src/components/inputs/inputNumber/index.vue +11 -83
- package/src/components/pageSubtitle/index.vue +7 -1
- package/src/components/pageTitle/index.vue +1 -0
- package/src/TestChart.vue +0 -229
package/package.json
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
<svg
|
2
|
-
<
|
3
|
-
<path d="M24.9592 15.0408C22.2382 12.3197 17.7618 12.3197 15.0408 15.0408C12.3197 17.7618 12.3197 22.2382 15.0408 24.9592C17.7618 27.6803 22.2382 27.6803 24.9592 24.9592C27.6803 22.2382 27.6803 17.8495 24.9592 15.0408ZM23.6426 22.5016L22.4138 23.7304L19.9561 21.2727L17.4984 23.7304L16.2696 22.5016L18.7273 20.0439L16.2696 17.5862L17.4984 16.3574L19.9561 18.815L22.4138 16.3574L23.6426 17.5862L21.185 20.0439L23.6426 22.5016Z" fill="#FF5656"></path>
|
1
|
+
<svg width="22" height="21" viewBox="0 0 22 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
2
|
+
<path d="M18.4389 3.06113C14.3574 -1.02038 7.64263 -1.02038 3.56113 3.06113C-0.520376 7.14263 -0.520376 13.8574 3.56113 17.9389C7.64263 22.0204 14.3574 22.0204 18.4389 17.9389C22.5204 13.8574 22.5204 7.2743 18.4389 3.06113ZM16.464 14.2524L14.6207 16.0956L10.9342 12.4091L7.24765 16.0956L5.40439 14.2524L9.09091 10.5658L5.40439 6.87931L7.24765 5.03605L10.9342 8.72257L14.6207 5.03605L16.464 6.87931L12.7774 10.5658L16.464 14.2524Z" fill="#FF5656"/>
|
4
3
|
</svg>
|
package/src/assets/theme.js
CHANGED
@@ -333,7 +333,7 @@ const theme = (() => {
|
|
333
333
|
borderColor: semanticColors.grey[300],
|
334
334
|
},
|
335
335
|
active: {
|
336
|
-
backgroundColor: semanticColors.purple[
|
336
|
+
backgroundColor: semanticColors.purple[50],
|
337
337
|
textColor: semanticColors.purple[600],
|
338
338
|
borderColor: semanticColors.grey[600],
|
339
339
|
},
|
@@ -1,14 +1,14 @@
|
|
1
1
|
<template>
|
2
2
|
<Container :is-chart-controls-shown-in-bottom="isChartControlsShownInBottom">
|
3
3
|
<LabelsColumn :width="yAxisWidth">
|
4
|
-
<LabelRow v-for="series in
|
4
|
+
<LabelRow v-for="series in props.series" :key="series.name">
|
5
5
|
{{ series.name }}
|
6
6
|
</LabelRow>
|
7
|
-
<TotalRow v-if="
|
8
|
-
{{ $gettext ?
|
7
|
+
<TotalRow v-if="props.series.length && fieldMode === 'percentage'">
|
8
|
+
{{ $gettext ? $gettext('Total (%)') : 'Total (%)' }}
|
9
9
|
</TotalRow>
|
10
|
-
<TotalRow v-if="
|
11
|
-
{{ $gettext ?
|
10
|
+
<TotalRow v-if="props.series.length">
|
11
|
+
{{ $gettext ? $gettext('Total (kWh)') : 'Total (kWh)' }}
|
12
12
|
</TotalRow>
|
13
13
|
</LabelsColumn>
|
14
14
|
|
@@ -18,35 +18,27 @@
|
|
18
18
|
>
|
19
19
|
<FieldsWrapper>
|
20
20
|
<!-- For stacked bar chart -->
|
21
|
-
<template v-if="
|
21
|
+
<template v-if="props.series.length">
|
22
22
|
<InputRow
|
23
|
-
v-for="series in
|
23
|
+
v-for="series in props.series"
|
24
24
|
:key="series.name"
|
25
25
|
:data-series-name="series.name"
|
26
26
|
>
|
27
27
|
<InputGroup
|
28
28
|
v-for="(item, index) in props.data"
|
29
|
-
:key="index"
|
30
29
|
:bar-width="barWidth"
|
31
30
|
:is-scrollable="isScrollable"
|
31
|
+
:key="index"
|
32
32
|
>
|
33
33
|
<InputNumber
|
34
34
|
:allow-negative="false"
|
35
|
-
:disabled="isInputsDisabled"
|
36
35
|
input-height="36px"
|
37
|
-
:
|
38
|
-
fieldMode === 'percentage'
|
39
|
-
? calculatePercentageTotal(item.label) !== 100
|
40
|
-
: false
|
41
|
-
"
|
36
|
+
:number-precision="0"
|
42
37
|
:min-decimals="0"
|
43
|
-
:number-precision="fieldMode === 'percentage' ? 2 : 0"
|
44
38
|
text-align="center"
|
45
39
|
:unit-name="fieldMode === 'percentage' ? '%' : ''"
|
46
40
|
:value="getDisplayValue(series.data, item.label)"
|
47
|
-
@input-blur="
|
48
|
-
handleInputBlur($event, series.name, item.label, series.data)
|
49
|
-
"
|
41
|
+
@input-blur="handleInputBlur($event, series.name, item.label)"
|
50
42
|
@input-focus="handleInputFocus(series.name, item.label)"
|
51
43
|
/>
|
52
44
|
</InputGroup>
|
@@ -55,17 +47,16 @@
|
|
55
47
|
<TotalInputRow v-if="fieldMode === 'percentage'">
|
56
48
|
<InputGroup
|
57
49
|
v-for="(item, index) in props.data"
|
58
|
-
:key="index"
|
59
50
|
:bar-width="barWidth"
|
60
51
|
:is-scrollable="isScrollable"
|
52
|
+
:key="index"
|
61
53
|
>
|
62
54
|
<InputNumber
|
63
55
|
:allow-negative="false"
|
64
|
-
:disabled="isInputsDisabled"
|
65
56
|
input-height="36px"
|
66
57
|
:is-read-only="true"
|
58
|
+
:number-precision="0"
|
67
59
|
:min-decimals="0"
|
68
|
-
:number-precision="fieldMode === 'percentage' ? 2 : 0"
|
69
60
|
text-align="center"
|
70
61
|
:unit-name="fieldMode === 'percentage' ? '%' : ''"
|
71
62
|
:value="calculatePercentageTotal(item.label)"
|
@@ -76,23 +67,17 @@
|
|
76
67
|
<TotalInputRow>
|
77
68
|
<InputGroup
|
78
69
|
v-for="(item, index) in props.data"
|
79
|
-
:key="index"
|
80
70
|
:bar-width="barWidth"
|
81
71
|
:is-scrollable="isScrollable"
|
72
|
+
:key="index"
|
82
73
|
>
|
83
74
|
<InputNumber
|
84
75
|
input-height="36px"
|
85
|
-
:is-border-error-only="true"
|
86
|
-
:is-info-border="
|
87
|
-
fieldMode === 'percentage'
|
88
|
-
? calculatePercentageTotal(item.label) !== 100
|
89
|
-
: false
|
90
|
-
"
|
91
76
|
:is-read-only="true"
|
77
|
+
:number-precision="2"
|
92
78
|
:min-decimals="0"
|
93
|
-
:number-precision="0"
|
94
79
|
text-align="center"
|
95
|
-
:value="
|
80
|
+
:value="calculateTotal(item.label)"
|
96
81
|
/>
|
97
82
|
</InputGroup>
|
98
83
|
</TotalInputRow>
|
@@ -103,19 +88,17 @@
|
|
103
88
|
<InputRow>
|
104
89
|
<InputGroup
|
105
90
|
v-for="(item, index) in props.data"
|
106
|
-
:key="index"
|
107
91
|
:bar-width="barWidth"
|
108
92
|
:is-scrollable="isScrollable"
|
93
|
+
:key="index"
|
109
94
|
>
|
110
95
|
<InputNumber
|
111
|
-
:allow-negative="false"
|
112
|
-
:disabled="isInputsDisabled"
|
113
96
|
input-height="36px"
|
114
97
|
:min-decimals="0"
|
115
|
-
:number-precision="
|
98
|
+
:number-precision="2"
|
116
99
|
text-align="center"
|
117
100
|
:value="item.value"
|
118
|
-
@input-blur="handleInputBlur($event, null, item.label
|
101
|
+
@input-blur="handleInputBlur($event, null, item.label)"
|
119
102
|
@input-focus="handleInputFocus(null, item.label)"
|
120
103
|
/>
|
121
104
|
</InputGroup>
|
@@ -124,22 +107,11 @@
|
|
124
107
|
</FieldsWrapper>
|
125
108
|
</FieldsContainer>
|
126
109
|
</Container>
|
127
|
-
<InfoCardContainer
|
128
|
-
v-if="hasAnySegmentNotTotatTo100Percent && fieldMode === 'percentage'"
|
129
|
-
:yAxisWidth="yAxisWidth"
|
130
|
-
>
|
131
|
-
<InfoCard align-items="center" type="info">
|
132
|
-
<InfoCardBody>
|
133
|
-
{{ $gettext('load_profile_not_add_up_to_100') }}
|
134
|
-
</InfoCardBody>
|
135
|
-
</InfoCard>
|
136
|
-
</InfoCardContainer>
|
137
110
|
</template>
|
138
111
|
|
139
112
|
<script setup>
|
140
|
-
import { ref
|
113
|
+
import { ref } from 'vue'
|
141
114
|
import InputNumber from '../inputs/inputNumber'
|
142
|
-
import InfoCard from '../infoCard'
|
143
115
|
|
144
116
|
import {
|
145
117
|
Container,
|
@@ -151,8 +123,6 @@
|
|
151
123
|
InputRow,
|
152
124
|
TotalInputRow,
|
153
125
|
InputGroup,
|
154
|
-
InfoCardContainer,
|
155
|
-
InfoCardBody,
|
156
126
|
} from './styles/bottomFields'
|
157
127
|
|
158
128
|
const props = defineProps({
|
@@ -189,47 +159,6 @@
|
|
189
159
|
default: 'absolute',
|
190
160
|
validator: (value) => ['absolute', 'percentage'].includes(value),
|
191
161
|
},
|
192
|
-
isInputsDisabled: {
|
193
|
-
type: Boolean,
|
194
|
-
default: false,
|
195
|
-
},
|
196
|
-
})
|
197
|
-
|
198
|
-
const seriesData = ref([])
|
199
|
-
|
200
|
-
watchEffect(() => {
|
201
|
-
let isNewSetOfSeries = false
|
202
|
-
const seriesDataCopy = [...seriesData.value]
|
203
|
-
if (
|
204
|
-
!seriesDataCopy.length ||
|
205
|
-
!props.series.length ||
|
206
|
-
seriesDataCopy.length !== props.series.length ||
|
207
|
-
!seriesDataCopy.some((item) => {
|
208
|
-
return props.series.map((s) => s.name).includes(item.name)
|
209
|
-
})
|
210
|
-
) {
|
211
|
-
isNewSetOfSeries = true
|
212
|
-
}
|
213
|
-
const currentSeriesData = !isNewSetOfSeries ? seriesDataCopy : []
|
214
|
-
const newSeriesData = []
|
215
|
-
|
216
|
-
props.series.forEach((item, itemIndex) => {
|
217
|
-
const data = item.data.map((d, dIndex) => ({
|
218
|
-
label: d.label,
|
219
|
-
value: d.value,
|
220
|
-
percentage: d.percentage,
|
221
|
-
originalValue: currentSeriesData.length
|
222
|
-
? currentSeriesData[itemIndex].data[dIndex].originalValue
|
223
|
-
: d.value,
|
224
|
-
}))
|
225
|
-
|
226
|
-
newSeriesData.push({
|
227
|
-
name: item.name,
|
228
|
-
data,
|
229
|
-
})
|
230
|
-
})
|
231
|
-
|
232
|
-
seriesData.value = [...newSeriesData]
|
233
162
|
})
|
234
163
|
|
235
164
|
const emit = defineEmits([
|
@@ -246,13 +175,11 @@
|
|
246
175
|
emit('input-focus', { seriesName, label })
|
247
176
|
}
|
248
177
|
|
249
|
-
const
|
250
|
-
|
178
|
+
const calculateTotal = (label) => {
|
179
|
+
return props.series.reduce((sum, series) => {
|
251
180
|
const value = series.data.find((d) => d.label === label)?.value || 0
|
252
181
|
return sum + value
|
253
182
|
}, 0)
|
254
|
-
|
255
|
-
return Math.round(total)
|
256
183
|
}
|
257
184
|
|
258
185
|
const syncScroll = (scrollLeft) => {
|
@@ -263,43 +190,34 @@
|
|
263
190
|
container.scrollLeft = scrollLeft
|
264
191
|
}
|
265
192
|
}
|
266
|
-
|
267
|
-
const calculateTotalOriginalValue = (label) => {
|
268
|
-
return seriesData.value.reduce((sum, series) => {
|
269
|
-
const value =
|
270
|
-
series.data.find((d) => d.label === label)?.originalValue || 0
|
271
|
-
return sum + value
|
272
|
-
}, 0)
|
273
|
-
}
|
274
|
-
|
275
|
-
const getDisplayValue = (data, label, shouldRound = true) => {
|
193
|
+
const getDisplayValue = (seriesData, label) => {
|
276
194
|
if (props.fieldMode === 'absolute') {
|
277
|
-
return
|
195
|
+
return seriesData.find((d) => d.label === label)?.value || ''
|
278
196
|
}
|
279
197
|
|
280
|
-
|
198
|
+
const value = seriesData.find((d) => d.label === label)?.value || 0
|
199
|
+
const total = calculateTotal(label)
|
200
|
+
return total ? Number(((value / total) * 100).toFixed(0)) : 0
|
281
201
|
}
|
282
202
|
|
283
203
|
const calculatePercentageTotal = (label) => {
|
284
|
-
|
285
|
-
const
|
286
|
-
|
204
|
+
return props.series.reduce((sum, series) => {
|
205
|
+
const value = series.data.find((d) => d.label === label)?.value || 0
|
206
|
+
const total = calculateTotal(label)
|
207
|
+
const percentage = total ? Number(((value / total) * 100).toFixed(0)) : 0
|
287
208
|
return sum + percentage
|
288
209
|
}, 0)
|
289
|
-
|
290
|
-
return Math.round(percentageTotal)
|
291
210
|
}
|
292
211
|
|
293
|
-
const handleInputBlur = (_value, seriesName, label
|
212
|
+
const handleInputBlur = (_value, seriesName, label) => {
|
294
213
|
let value = Number(_value)
|
295
214
|
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
: { label, value }
|
215
|
+
if (props.fieldMode === 'percentage') {
|
216
|
+
const total = calculateTotal(label)
|
217
|
+
value = (value / 100) * total
|
218
|
+
}
|
219
|
+
|
220
|
+
const payload = seriesName ? { seriesName, label, value } : { label, value }
|
303
221
|
emit('input-blur', payload)
|
304
222
|
focusedInput.value = null
|
305
223
|
|
@@ -325,12 +243,6 @@
|
|
325
243
|
}
|
326
244
|
}
|
327
245
|
|
328
|
-
const hasAnySegmentNotTotatTo100Percent = computed(() => {
|
329
|
-
return props.data.some((d) => {
|
330
|
-
return calculatePercentageTotal(d.label) !== 100
|
331
|
-
})
|
332
|
-
})
|
333
|
-
|
334
246
|
const handleFieldsScroll = (event) => {
|
335
247
|
emit('sync-scroll', event.target.scrollLeft)
|
336
248
|
}
|
@@ -84,7 +84,7 @@ export function useAxisCalculations(props, maxValue) {
|
|
84
84
|
})
|
85
85
|
|
86
86
|
const yAxisWidth = computed(() => {
|
87
|
-
return !!props.yAxisTitle || props.isBottomFieldsShown ? '
|
87
|
+
return !!props.yAxisTitle || props.isBottomFieldsShown ? '70px' : '60px'
|
88
88
|
})
|
89
89
|
|
90
90
|
const isChartControlsShown = (position) => {
|
@@ -66,7 +66,7 @@ export function useChartData(props, paddedMaxValue) {
|
|
66
66
|
let accumulated = 0
|
67
67
|
return {
|
68
68
|
label: item.label,
|
69
|
-
segments: [...props.series].map((series, index) => {
|
69
|
+
segments: [...props.series].reverse().map((series, index) => {
|
70
70
|
const value =
|
71
71
|
series.data.find((d) => d.label === item.label)?.value || 0
|
72
72
|
accumulated += value
|
@@ -16,21 +16,7 @@ export function useTooltip(chartId, normalizedData) {
|
|
16
16
|
if (!showTooltipContent.value) {
|
17
17
|
showTooltipContent.value = true
|
18
18
|
}
|
19
|
-
if (isObjectEqual(item, tooltipData.value))
|
20
|
-
return
|
21
|
-
}
|
22
|
-
|
23
|
-
const totalValue = item.segments.reduce((acc, segment) => {
|
24
|
-
return acc + segment.value
|
25
|
-
}, 0)
|
26
|
-
|
27
|
-
const segments = item.segments.map((segment) => {
|
28
|
-
let valuePercentage = (segment.value / totalValue) * 100
|
29
|
-
segment.valuePercentage = Math.round(valuePercentage)
|
30
|
-
|
31
|
-
return segment
|
32
|
-
})
|
33
|
-
item.segments = segments
|
19
|
+
if (isObjectEqual(item, tooltipData.value)) return
|
34
20
|
|
35
21
|
tooltipData.value = { ...item }
|
36
22
|
|
@@ -55,27 +41,16 @@ export function useTooltip(chartId, normalizedData) {
|
|
55
41
|
|
56
42
|
isInputFocused.value = true
|
57
43
|
const barData = normalizedData.value.find((item) => item.label === label)
|
58
|
-
if (!barData) return
|
59
44
|
|
60
|
-
|
61
|
-
return acc + segment.value
|
62
|
-
}, 0)
|
63
|
-
const segments = barData.segments.map((segment) => {
|
64
|
-
let valuePercentage = (segment.value / totalValue) * 100
|
65
|
-
segment.valuePercentage = Math.round(valuePercentage)
|
66
|
-
|
67
|
-
return segment
|
68
|
-
})
|
69
|
-
barData.segments = segments
|
45
|
+
if (!barData) return
|
70
46
|
focusedBarData.value = barData
|
71
|
-
|
72
47
|
const barElement = document.querySelector(
|
73
48
|
`.barchart-${chartId} .bar-group:nth-child(${
|
74
49
|
normalizedData.value.indexOf(barData) + 1
|
75
50
|
})`
|
76
51
|
)
|
77
|
-
if (!barElement) return
|
78
52
|
|
53
|
+
if (!barElement) return
|
79
54
|
// Get the last bar segment, samee as hover behavior
|
80
55
|
const targetElement = barElement.querySelector('.bar-segment:last-child')
|
81
56
|
const rect = targetElement.getBoundingClientRect()
|
@@ -17,8 +17,8 @@
|
|
17
17
|
/>
|
18
18
|
</ChartControlsWrapper>
|
19
19
|
<GraphSection :height="height" :width="width">
|
20
|
-
<YAxis :
|
21
|
-
<YAxisTitleWrapper v-if="yAxisTitle"
|
20
|
+
<YAxis :width="yAxisWidth">
|
21
|
+
<YAxisTitleWrapper v-if="yAxisTitle">
|
22
22
|
{{ yAxisTitle }}
|
23
23
|
</YAxisTitleWrapper>
|
24
24
|
<YAxisRow
|
@@ -30,15 +30,15 @@
|
|
30
30
|
)
|
31
31
|
"
|
32
32
|
>
|
33
|
-
<YAxisLabel>{{
|
33
|
+
<YAxisLabel>{{ label }}</YAxisLabel>
|
34
34
|
<YAxisLine :y-axis-width="yAxisWidth" />
|
35
35
|
</YAxisRow>
|
36
36
|
</YAxis>
|
37
37
|
|
38
38
|
<ScrollContainer
|
39
39
|
:class="`chart-scroll-container-${chartId}`"
|
40
|
-
:height="height"
|
41
40
|
:is-scrollable="isScrollable"
|
41
|
+
:height="height"
|
42
42
|
@scroll="handleChartScroll"
|
43
43
|
>
|
44
44
|
<ChartContent
|
@@ -64,19 +64,19 @@
|
|
64
64
|
<BarsContainer>
|
65
65
|
<BarGroup
|
66
66
|
v-for="(item, index) in normalizedData"
|
67
|
-
:key="index"
|
68
67
|
:bar-width="barWidth"
|
69
68
|
class="bar-group"
|
70
69
|
:is-scrollable="isScrollable"
|
70
|
+
:key="index"
|
71
71
|
>
|
72
72
|
<BarWrapper>
|
73
73
|
<BarSegment
|
74
74
|
v-for="(segment, segIndex) in item.segments"
|
75
|
-
:key="segIndex"
|
76
75
|
class="bar-segment"
|
77
76
|
:gradient-from="getSegmentGradient(index, segment).from"
|
78
77
|
:gradient-to="getSegmentGradient(index, segment).to"
|
79
78
|
:height="`${segment.percentage}%`"
|
79
|
+
:key="segIndex"
|
80
80
|
:z-index="item.segments.length - segIndex"
|
81
81
|
@mouseenter="showTooltip(item, $event, series)"
|
82
82
|
@mouseleave="hideTooltip"
|
@@ -96,7 +96,7 @@
|
|
96
96
|
:left="tooltipStyle.left"
|
97
97
|
:top="tooltipStyle.top"
|
98
98
|
>
|
99
|
-
<slot :item="tooltipData" name="tooltip"
|
99
|
+
<slot :item="tooltipData" name="tooltip" />
|
100
100
|
<TooltipTextWrapper v-if="!slots.tooltip && tooltipData">
|
101
101
|
<template v-if="!series.length">
|
102
102
|
<TooltipText font-weight="500">{{ tooltipData.label }}</TooltipText>
|
@@ -128,11 +128,7 @@
|
|
128
128
|
:gradient-to="segment.gradientTo"
|
129
129
|
/>
|
130
130
|
<TooltipText>
|
131
|
-
{{
|
132
|
-
fieldMode === 'absolute' && showPercentageOnTooltip
|
133
|
-
? `${segment.valuePercentage}%`
|
134
|
-
: handleValueFormatter(segment.value)
|
135
|
-
}}
|
131
|
+
{{ handleValueFormatter(segment.value) }}
|
136
132
|
</TooltipText>
|
137
133
|
</TooltipRow>
|
138
134
|
</template>
|
@@ -163,7 +159,6 @@
|
|
163
159
|
:data="data"
|
164
160
|
:field-mode="fieldMode"
|
165
161
|
:is-chart-controls-shown-in-bottom="isChartControlsShown('bottom')"
|
166
|
-
:is-inputs-disabled="isLoading"
|
167
162
|
:is-scrollable="isScrollable"
|
168
163
|
:series="series"
|
169
164
|
:y-axis-width="yAxisWidth"
|
@@ -176,13 +171,12 @@
|
|
176
171
|
</template>
|
177
172
|
|
178
173
|
<script setup>
|
179
|
-
import { useSlots, computed
|
174
|
+
import { useSlots, computed } from 'vue'
|
180
175
|
|
181
176
|
import ChartControls from './ChartControls'
|
182
177
|
import BottomFields from './BottomFields'
|
183
178
|
import SelectionBox from './SelectionBox'
|
184
179
|
import Spinner from '../spinner'
|
185
|
-
import { numberToString } from '../../helpers/numberConverter'
|
186
180
|
|
187
181
|
import {
|
188
182
|
useTooltip,
|
@@ -252,6 +246,10 @@
|
|
252
246
|
type: String,
|
253
247
|
default: '',
|
254
248
|
},
|
249
|
+
valueFormatter: {
|
250
|
+
type: Function,
|
251
|
+
default: null,
|
252
|
+
},
|
255
253
|
isLegendShown: {
|
256
254
|
type: Boolean,
|
257
255
|
default: false,
|
@@ -298,10 +296,6 @@
|
|
298
296
|
type: Boolean,
|
299
297
|
default: false,
|
300
298
|
},
|
301
|
-
showPercentageOnTooltip: {
|
302
|
-
type: Boolean,
|
303
|
-
default: false,
|
304
|
-
},
|
305
299
|
})
|
306
300
|
|
307
301
|
const generateChartId = () =>
|
@@ -384,40 +378,8 @@
|
|
384
378
|
}
|
385
379
|
|
386
380
|
const handleValueFormatter = (value) => {
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
value: formattedValue,
|
391
|
-
numberPrecision: 0,
|
392
|
-
minDecimals: 0,
|
393
|
-
})
|
394
|
-
} else if (value < 1000000) {
|
395
|
-
formattedValue = numberToString({
|
396
|
-
value: Number(formattedValue / 1000),
|
397
|
-
numberPrecision: 2,
|
398
|
-
minDecimals: 2,
|
399
|
-
})
|
400
|
-
} else {
|
401
|
-
formattedValue = numberToString({
|
402
|
-
value: Number(formattedValue / 1000000),
|
403
|
-
numberPrecision: 2,
|
404
|
-
minDecimals: 2,
|
405
|
-
})
|
406
|
-
}
|
407
|
-
if (value < 1000) {
|
408
|
-
return `${formattedValue} kWh`
|
409
|
-
} else if (value < 1000000) {
|
410
|
-
return `${formattedValue} MWh`
|
411
|
-
} else {
|
412
|
-
return `${formattedValue} GWh`
|
413
|
-
}
|
414
|
-
}
|
415
|
-
|
416
|
-
const getYAxisLabel = (label) => {
|
417
|
-
return numberToString({
|
418
|
-
value: label,
|
419
|
-
numberPrecision: 0,
|
420
|
-
minDecimals: 0,
|
421
|
-
})
|
381
|
+
return props.valueFormatter
|
382
|
+
? props.valueFormatter(Math.round(value))
|
383
|
+
: value
|
422
384
|
}
|
423
385
|
</script>
|
@@ -17,18 +17,18 @@ export const LabelsColumn = styled('div', { width: String })`
|
|
17
17
|
|
18
18
|
export const LabelRow = styled.div`
|
19
19
|
height: 32px;
|
20
|
-
padding-top: 5px;
|
21
20
|
font-size: 12px;
|
22
21
|
font-weight: 500;
|
23
22
|
color: ${(props) => props.theme.semanticColors.teal[600]};
|
24
23
|
display: flex;
|
25
|
-
align-items:
|
24
|
+
align-items: flex-start;
|
26
25
|
`
|
27
26
|
|
28
27
|
export const TotalRow = styled(LabelRow)``
|
29
28
|
|
30
29
|
export const FieldsContainer = styled.div`
|
31
30
|
flex: 1;
|
31
|
+
overflow-x: auto;
|
32
32
|
scrollbar-width: none;
|
33
33
|
|
34
34
|
&::-webkit-scrollbar {
|
@@ -59,22 +59,8 @@ export const InputGroup = styled('div', {
|
|
59
59
|
barWidth: Number,
|
60
60
|
isScrollable: Boolean,
|
61
61
|
})`
|
62
|
-
${(props) => (props.isScrollable ? 'min-width' : 'width')}
|
62
|
+
${(props) => (props.isScrollable ? 'min-width' : 'width')}:${(props) =>
|
63
|
+
props.barWidth}px;
|
63
64
|
display: flex;
|
64
65
|
justify-content: center;
|
65
|
-
position: relative;
|
66
|
-
|
67
|
-
input[readonly] {
|
68
|
-
border: 1px solid ${(props) => props.theme.colors.grey4} !important;
|
69
|
-
}
|
70
|
-
`
|
71
|
-
|
72
|
-
export const InfoCardContainer = styled('div', { yAxisWidth: String })`
|
73
|
-
margin-left: ${(props) => props.yAxisWidth};
|
74
|
-
padding: 12px;
|
75
|
-
margin-top: 12px;
|
76
|
-
`
|
77
|
-
|
78
|
-
export const InfoCardBody = styled.div`
|
79
|
-
padding: 8px 0;
|
80
66
|
`
|
@@ -16,12 +16,9 @@ export const GraphSection = styled('div', { width: String, height: String })`
|
|
16
16
|
display: flex;
|
17
17
|
`
|
18
18
|
|
19
|
-
export const YAxis = styled('div', { width: String
|
19
|
+
export const YAxis = styled('div', { width: String })`
|
20
20
|
width: ${(props) => props.width};
|
21
|
-
display: flex;
|
22
|
-
flex-direction: column;
|
23
21
|
position: relative;
|
24
|
-
height: ${(props) => props.height};
|
25
22
|
`
|
26
23
|
|
27
24
|
export const YAxisRow = styled('div', { percentage: Number })`
|
@@ -57,18 +54,19 @@ export const YAxisLine = styled('div', { yAxisWidth: String })`
|
|
57
54
|
transform: translateY(-50%);
|
58
55
|
`
|
59
56
|
|
60
|
-
export const YAxisTitleWrapper = styled('div'
|
61
|
-
position: absolute;
|
62
|
-
left: -66px;
|
63
|
-
top: ${(props) => props.height};
|
64
|
-
transform: rotate(-90deg) translateX(50%);
|
65
|
-
transform-origin: right;
|
57
|
+
export const YAxisTitleWrapper = styled('div')`
|
66
58
|
font-size: 12px;
|
67
|
-
|
68
|
-
|
69
|
-
align-items: center;
|
59
|
+
font-weight: 500;
|
60
|
+
color: ${(props) => props.theme.semanticColors.grey[700]};
|
70
61
|
white-space: nowrap;
|
71
|
-
|
62
|
+
height: 0;
|
63
|
+
width: 0;
|
64
|
+
display: flex;
|
65
|
+
align-items: flex-start;
|
66
|
+
justify-content: center;
|
67
|
+
position: absolute;
|
68
|
+
top: 50%;
|
69
|
+
transform: rotate(-90deg);
|
72
70
|
`
|
73
71
|
|
74
72
|
export const ScrollContainer = styled('div', {
|
@@ -127,7 +125,6 @@ export const BarWrapper = styled.div`
|
|
127
125
|
height: 100%;
|
128
126
|
width: 100%;
|
129
127
|
position: relative;
|
130
|
-
overflow: hidden;
|
131
128
|
`
|
132
129
|
|
133
130
|
export const BarSegment = styled('div', {
|
@@ -73,12 +73,7 @@
|
|
73
73
|
type: {
|
74
74
|
required: false,
|
75
75
|
type: String,
|
76
|
-
default: '
|
77
|
-
validator(value) {
|
78
|
-
return ['info_simple', 'warning', 'error_minor', 'info'].includes(
|
79
|
-
value
|
80
|
-
)
|
81
|
-
},
|
76
|
+
default: 'info',
|
82
77
|
},
|
83
78
|
minWidth: {
|
84
79
|
required: false,
|
@@ -117,11 +112,8 @@
|
|
117
112
|
},
|
118
113
|
},
|
119
114
|
computed: {
|
120
|
-
isInfoSimple() {
|
121
|
-
// this property is used for tests
|
122
|
-
return this.type === 'info_simple'
|
123
|
-
},
|
124
115
|
isInfo() {
|
116
|
+
// this property is used for tests
|
125
117
|
return this.type === 'info'
|
126
118
|
},
|
127
119
|
isWarning() {
|
@@ -156,13 +148,9 @@
|
|
156
148
|
stylesCollection.borderStyle = 'dashed'
|
157
149
|
stylesCollection.borderColor = theme.colors.grey4
|
158
150
|
stylesCollection.iconColor = theme.colors.red
|
159
|
-
} else
|
151
|
+
} else {
|
160
152
|
stylesCollection.borderStyle = 'dashed'
|
161
153
|
stylesCollection.borderColor = theme.colors.grey4
|
162
|
-
} else {
|
163
|
-
stylesCollection.color = theme.semanticColors.teal[800]
|
164
|
-
stylesCollection.backgroundColor = theme.semanticColors.blue[300]
|
165
|
-
stylesCollection.iconColor = theme.semanticColors.teal[800]
|
166
154
|
}
|
167
155
|
|
168
156
|
return stylesCollection
|
@@ -45,19 +45,19 @@ describe('RCInfoCard.vue', () => {
|
|
45
45
|
},
|
46
46
|
})
|
47
47
|
|
48
|
-
expect(wrapper.vm.
|
48
|
+
expect(wrapper.vm.isInfo).toBe(true)
|
49
49
|
expect(wrapper.vm.isWarning).toBe(false)
|
50
50
|
expect(wrapper.vm.isErrorMinor).toBe(false)
|
51
51
|
|
52
52
|
await wrapper.setProps({ type: 'warning' })
|
53
53
|
|
54
|
-
expect(wrapper.vm.
|
54
|
+
expect(wrapper.vm.isInfo).toBe(false)
|
55
55
|
expect(wrapper.vm.isWarning).toBe(true)
|
56
56
|
expect(wrapper.vm.isErrorMinor).toBe(false)
|
57
57
|
|
58
58
|
await wrapper.setProps({ type: 'error_minor' })
|
59
59
|
|
60
|
-
expect(wrapper.vm.
|
60
|
+
expect(wrapper.vm.isInfo).toBe(false)
|
61
61
|
expect(wrapper.vm.isWarning).toBe(false)
|
62
62
|
expect(wrapper.vm.isErrorMinor).toBe(true)
|
63
63
|
})
|
@@ -15,40 +15,37 @@
|
|
15
15
|
:is-disabled="isDisabled"
|
16
16
|
:padding="padding"
|
17
17
|
>
|
18
|
-
<
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
</LabelWrapper>
|
47
|
-
</template>
|
48
|
-
<slot name="trigger"></slot>
|
18
|
+
<LabelWrapper
|
19
|
+
v-if="labelText && labelAlign === 'left'"
|
20
|
+
:color="iconColor || computedIconColor"
|
21
|
+
:size="labelSize"
|
22
|
+
>
|
23
|
+
{{ labelText }}
|
24
|
+
</LabelWrapper>
|
25
|
+
<Dot
|
26
|
+
v-if="type === 'dot'"
|
27
|
+
:color="dotColor"
|
28
|
+
data-test-id="infoText_dot"
|
29
|
+
/>
|
30
|
+
<IconComponent
|
31
|
+
v-else-if="!noIcon"
|
32
|
+
:color="iconColor || computedIconColor"
|
33
|
+
:cursor="isDisabled ? 'not-allowed' : 'pointer'"
|
34
|
+
:disabled="isDisabled"
|
35
|
+
:hovered-color="iconColor || computedIconColor"
|
36
|
+
:name="iconName"
|
37
|
+
:size="size"
|
38
|
+
/>
|
39
|
+
<LabelWrapper
|
40
|
+
v-if="labelText && labelAlign === 'right'"
|
41
|
+
:color="iconColor || computedIconColor"
|
42
|
+
:size="labelSize"
|
43
|
+
>
|
44
|
+
{{ labelText }}
|
45
|
+
</LabelWrapper>
|
49
46
|
</IconWrapper>
|
50
47
|
</div>
|
51
|
-
<Teleport v-if="isVisible
|
48
|
+
<Teleport v-if="isVisible" to="body">
|
52
49
|
<TextWrapper data-test-id="info_text_wrapper" :style="wrapperStyle">
|
53
50
|
<TextOverlay
|
54
51
|
ref="infoBox"
|
@@ -230,7 +227,7 @@
|
|
230
227
|
},
|
231
228
|
infoPosition: {
|
232
229
|
required: false,
|
233
|
-
default:
|
230
|
+
default: 'bottom',
|
234
231
|
type: String,
|
235
232
|
},
|
236
233
|
maxWidth: {
|
@@ -366,9 +363,7 @@
|
|
366
363
|
{ position: 'left', space: spaceLeft },
|
367
364
|
].sort((a, b) => b.space - a.space)
|
368
365
|
|
369
|
-
const bestPosition =
|
370
|
-
? props.infoPosition
|
371
|
-
: positions[0].position
|
366
|
+
const bestPosition = positions[0].position
|
372
367
|
|
373
368
|
let top, left, arrowPosition
|
374
369
|
|
@@ -3,15 +3,15 @@ import InputNumber from './index.vue'
|
|
3
3
|
export default {
|
4
4
|
title: 'InputNumber',
|
5
5
|
component: InputNumber,
|
6
|
-
// argTypes: {},
|
7
6
|
}
|
8
7
|
|
9
|
-
const Template = (args
|
8
|
+
const Template = (args) => ({
|
10
9
|
// Components used in your story `template` are defined in the `components` object
|
11
10
|
components: { InputNumber },
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
setup() {
|
12
|
+
return { args: args }
|
13
|
+
},
|
14
|
+
template: `<InputNumber v-bind="args" />`,
|
15
15
|
|
16
16
|
// import InputNumber from "@eturnity/eturnity_reusable_components/src/components/inputs/inputNumber"
|
17
17
|
// How to use:
|
@@ -30,61 +30,7 @@
|
|
30
30
|
/>
|
31
31
|
</LabelWrapper>
|
32
32
|
<InputWrapper>
|
33
|
-
<InfoText
|
34
|
-
v-if="!!inputInfoText"
|
35
|
-
info-position="bottom"
|
36
|
-
:text="inputInfoText"
|
37
|
-
>
|
38
|
-
<template #trigger>
|
39
|
-
<InputContainer
|
40
|
-
v-bind="$attrs"
|
41
|
-
ref="inputField1"
|
42
|
-
:align-items="alignItems"
|
43
|
-
:background-color="
|
44
|
-
colorMode === 'transparent' ? 'transparent' : backgroundColor
|
45
|
-
"
|
46
|
-
:border-color="
|
47
|
-
colorMode === 'transparent' && !borderColor
|
48
|
-
? 'white'
|
49
|
-
: borderColor
|
50
|
-
"
|
51
|
-
:color-mode="colorMode"
|
52
|
-
:data-id="inputDataId"
|
53
|
-
:data-qa-id="dataQaId"
|
54
|
-
:disabled="disabled"
|
55
|
-
:font-color="colorMode === 'transparent' ? 'white' : fontColor"
|
56
|
-
:font-size="fontSize"
|
57
|
-
:has-label-slot="hasLabelSlot"
|
58
|
-
:has-slot="hasSlot"
|
59
|
-
:has-unit="unitName && !!unitName.length"
|
60
|
-
:input-height="inputHeight"
|
61
|
-
:is-border-error-only="isBorderErrorOnly"
|
62
|
-
:is-disabled="disabled"
|
63
|
-
:is-error="isError"
|
64
|
-
:is-info-border="isInfoBorder"
|
65
|
-
:is-interactive="isInteractive"
|
66
|
-
:min-width="minWidth"
|
67
|
-
:no-border="noBorder"
|
68
|
-
:placeholder="displayedPlaceholder"
|
69
|
-
:read-only="isReadOnly"
|
70
|
-
:readonly="isReadOnly"
|
71
|
-
:show-arrow-controls="showArrowControls"
|
72
|
-
:show-linear-unit-name="showLinearUnitName"
|
73
|
-
:slot-size="slotSize"
|
74
|
-
:text-align="textAlign"
|
75
|
-
:value="formatWithCurrency(value)"
|
76
|
-
@blur="onInputBlur($event)"
|
77
|
-
@focus="focusInput()"
|
78
|
-
@input="onInput($event)"
|
79
|
-
@keydown.down="decrementValue"
|
80
|
-
@keydown.up="incrementValue"
|
81
|
-
@keyup.enter="onEnterPress"
|
82
|
-
/>
|
83
|
-
</template>
|
84
|
-
</InfoText>
|
85
|
-
|
86
33
|
<InputContainer
|
87
|
-
v-else
|
88
34
|
v-bind="$attrs"
|
89
35
|
ref="inputField1"
|
90
36
|
:align-items="alignItems"
|
@@ -97,23 +43,19 @@
|
|
97
43
|
:color-mode="colorMode"
|
98
44
|
:data-id="inputDataId"
|
99
45
|
:data-qa-id="dataQaId"
|
100
|
-
:disabled="disabled"
|
101
46
|
:font-color="colorMode === 'transparent' ? 'white' : fontColor"
|
102
47
|
:font-size="fontSize"
|
103
48
|
:has-label-slot="hasLabelSlot"
|
104
49
|
:has-slot="hasSlot"
|
105
50
|
:has-unit="unitName && !!unitName.length"
|
106
51
|
:input-height="inputHeight"
|
107
|
-
:is-border-error-only="isBorderErrorOnly"
|
108
52
|
:is-disabled="disabled"
|
109
53
|
:is-error="isError"
|
110
|
-
:is-info-border="isInfoBorder"
|
111
54
|
:is-interactive="isInteractive"
|
112
55
|
:min-width="minWidth"
|
113
56
|
:no-border="noBorder"
|
114
57
|
:placeholder="displayedPlaceholder"
|
115
58
|
:read-only="isReadOnly"
|
116
|
-
:readonly="isReadOnly"
|
117
59
|
:show-arrow-controls="showArrowControls"
|
118
60
|
:show-linear-unit-name="showLinearUnitName"
|
119
61
|
:slot-size="slotSize"
|
@@ -126,7 +68,6 @@
|
|
126
68
|
@keydown.up="incrementValue"
|
127
69
|
@keyup.enter="onEnterPress"
|
128
70
|
/>
|
129
|
-
|
130
71
|
<SlotContainer v-if="hasSlot" :is-error="isError" :slot-size="slotSize">
|
131
72
|
<slot></slot>
|
132
73
|
</SlotContainer>
|
@@ -138,7 +79,7 @@
|
|
138
79
|
>{{ unitName }}</UnitContainer
|
139
80
|
>
|
140
81
|
<IconWrapper
|
141
|
-
v-if="isError && !showLinearUnitName
|
82
|
+
v-if="isError && !showLinearUnitName"
|
142
83
|
:margin-right="showSelect ? selectWidth : 0"
|
143
84
|
size="16px"
|
144
85
|
>
|
@@ -192,9 +133,7 @@
|
|
192
133
|
</ArrowButton>
|
193
134
|
</ArrowControls>
|
194
135
|
</InputWrapper>
|
195
|
-
<ErrorMessage v-if="isError && errorMessage">{{
|
196
|
-
errorMessage
|
197
|
-
}}</ErrorMessage>
|
136
|
+
<ErrorMessage v-if="isError && errorMessage">{{ errorMessage }}</ErrorMessage>
|
198
137
|
</Container>
|
199
138
|
</template>
|
200
139
|
|
@@ -265,8 +204,6 @@
|
|
265
204
|
colorMode: String,
|
266
205
|
showArrowControls: Boolean,
|
267
206
|
readOnly: Boolean,
|
268
|
-
isBorderErrorOnly: Boolean,
|
269
|
-
isInfoBorder: Boolean,
|
270
207
|
}
|
271
208
|
|
272
209
|
const Container = styled('div', inputProps)`
|
@@ -279,9 +216,7 @@
|
|
279
216
|
|
280
217
|
const InputContainer = styled('input', inputProps)`
|
281
218
|
border: ${(props) =>
|
282
|
-
props.
|
283
|
-
? '1px solid ' + props.theme.semanticColors.blue[500]
|
284
|
-
: props.isError
|
219
|
+
props.isError
|
285
220
|
? '1px solid ' + props.theme.colors.red
|
286
221
|
: props.noBorder
|
287
222
|
? 'none'
|
@@ -300,17 +235,16 @@
|
|
300
235
|
showLinearUnitName,
|
301
236
|
colorMode,
|
302
237
|
showArrowControls,
|
303
|
-
isBorderErrorOnly,
|
304
238
|
}) =>
|
305
239
|
showArrowControls
|
306
240
|
? '40px'
|
307
241
|
: colorMode === 'transparent'
|
308
242
|
? '0'
|
309
243
|
: slotSize
|
310
|
-
? isError && !showLinearUnitName
|
244
|
+
? isError && !showLinearUnitName
|
311
245
|
? 'calc(' + slotSize + ' + 24px)'
|
312
246
|
: 'calc(' + slotSize + ' + 10px)'
|
313
|
-
: isError && !showLinearUnitName
|
247
|
+
: isError && !showLinearUnitName
|
314
248
|
? '24px'
|
315
249
|
: '5px'};
|
316
250
|
border-radius: ${(props) =>
|
@@ -723,12 +657,18 @@
|
|
723
657
|
required: false,
|
724
658
|
default: '',
|
725
659
|
},
|
660
|
+
labelDataTestId: {
|
661
|
+
type: String,
|
662
|
+
required: false,
|
663
|
+
default: '',
|
664
|
+
},
|
726
665
|
inputDataId: {
|
727
666
|
type: String,
|
728
667
|
required: false,
|
729
668
|
default: '',
|
730
669
|
},
|
731
670
|
dataQaId: {
|
671
|
+
type: String,
|
732
672
|
required: false,
|
733
673
|
default: '',
|
734
674
|
},
|
@@ -764,18 +704,6 @@
|
|
764
704
|
type: Boolean,
|
765
705
|
default: false,
|
766
706
|
},
|
767
|
-
isBorderErrorOnly: {
|
768
|
-
type: Boolean,
|
769
|
-
default: false,
|
770
|
-
},
|
771
|
-
isInfoBorder: {
|
772
|
-
type: Boolean,
|
773
|
-
default: false,
|
774
|
-
},
|
775
|
-
inputInfoText: {
|
776
|
-
type: String,
|
777
|
-
default: '',
|
778
|
-
},
|
779
707
|
},
|
780
708
|
data() {
|
781
709
|
return {
|
@@ -5,7 +5,8 @@
|
|
5
5
|
:has-info-text="!!infoText"
|
6
6
|
:margin-bottom="marginBottom"
|
7
7
|
>
|
8
|
-
<span data-test-id="page_subtitle_text">
|
8
|
+
<span v-if="containsHtml" data-test-id="page_subtitle_text" v-html="text"></span>
|
9
|
+
<span v-else data-test-id="page_subtitle_text">
|
9
10
|
{{ text }}
|
10
11
|
</span>
|
11
12
|
<InfoText
|
@@ -58,6 +59,11 @@
|
|
58
59
|
required: true,
|
59
60
|
type: String,
|
60
61
|
},
|
62
|
+
containsHtml: {
|
63
|
+
required: false,
|
64
|
+
type: Boolean,
|
65
|
+
default: false,
|
66
|
+
},
|
61
67
|
color: {
|
62
68
|
required: false,
|
63
69
|
type: String,
|
@@ -46,6 +46,7 @@
|
|
46
46
|
color: ${(props) => (props.color ? props.color : props.theme.colors.black)};
|
47
47
|
font-weight: 600;
|
48
48
|
font-size: ${(props) => (props.fontSize ? props.fontSize : '20px')};
|
49
|
+
text-transform: ${(props) => (props.uppercase ? 'uppercase' : 'none')};
|
49
50
|
`
|
50
51
|
|
51
52
|
export default {
|
package/src/TestChart.vue
DELETED
@@ -1,229 +0,0 @@
|
|
1
|
-
<template>
|
2
|
-
<div
|
3
|
-
style="
|
4
|
-
margin-top: 100px;
|
5
|
-
margin-left: 80px;
|
6
|
-
padding-bottom: 100px;
|
7
|
-
display: flex;
|
8
|
-
flex-direction: column;
|
9
|
-
"
|
10
|
-
>
|
11
|
-
<!-- Simple bar chart -->
|
12
|
-
<BarChart
|
13
|
-
:bar-width="60"
|
14
|
-
chart-controls-position="bottom"
|
15
|
-
:data="monthlyData"
|
16
|
-
height="400px"
|
17
|
-
:is-bottom-fields-shown="true"
|
18
|
-
:is-scrollable="false"
|
19
|
-
:is-selection-enabled="true"
|
20
|
-
:selection-size="3"
|
21
|
-
:value-formatter="valueFormatter"
|
22
|
-
width="700px"
|
23
|
-
@selection-change="handleSelectionChange"
|
24
|
-
/>
|
25
|
-
<br />
|
26
|
-
<br />
|
27
|
-
|
28
|
-
<!-- Stacked bar chart -->
|
29
|
-
<BarChart
|
30
|
-
:bar-width="60"
|
31
|
-
:data="monthLabels"
|
32
|
-
height="400px"
|
33
|
-
:is-bottom-fields-shown="true"
|
34
|
-
:is-legend-shown="true"
|
35
|
-
:legends-item-per-row="4"
|
36
|
-
:selected-split-button="selectedTimeFrame"
|
37
|
-
:series="tariffZones"
|
38
|
-
:show-percentage-on-tooltip="true"
|
39
|
-
:split-button-options="options"
|
40
|
-
:value-formatter="valueFormatter"
|
41
|
-
width="700px"
|
42
|
-
y-axis-title="Energy (kWh)"
|
43
|
-
@input-blur="handleInputBlur"
|
44
|
-
@select-split-button="handleSelectSplitButton"
|
45
|
-
/>
|
46
|
-
|
47
|
-
<!-- Stacked bar chart -->
|
48
|
-
<BarChart
|
49
|
-
:bar-width="60"
|
50
|
-
:data="monthLabels"
|
51
|
-
field-mode="percentage"
|
52
|
-
height="400px"
|
53
|
-
:is-bottom-fields-shown="true"
|
54
|
-
:is-legend-shown="false"
|
55
|
-
:legends-item-per-row="4"
|
56
|
-
:series="tariffZones"
|
57
|
-
:value-formatter="valueFormatter"
|
58
|
-
width="700px"
|
59
|
-
@input-blur="handleInputBlur"
|
60
|
-
@select-split-button="handleSelectSplitButton"
|
61
|
-
>
|
62
|
-
<!-- <template #tooltip="{ item, segment }">
|
63
|
-
<div style="display: flex; flex-direction: column">
|
64
|
-
{{ $c.log(item, segment) }}
|
65
|
-
<div>{{ item.label }}</div>
|
66
|
-
<div>{{ item.segments[0].value }} kWh</div>
|
67
|
-
</div>
|
68
|
-
</template> -->
|
69
|
-
</BarChart>
|
70
|
-
</div>
|
71
|
-
</template>
|
72
|
-
|
73
|
-
<script setup>
|
74
|
-
import { ref } from 'vue'
|
75
|
-
import BarChart from '@/components/barchart/index.vue'
|
76
|
-
|
77
|
-
const options = [
|
78
|
-
{ label: 'Day', value: 'day' },
|
79
|
-
{ label: 'Month', value: 'month' },
|
80
|
-
{ label: 'Year', value: 'year' },
|
81
|
-
]
|
82
|
-
|
83
|
-
const selectedTimeFrame = ref('day')
|
84
|
-
|
85
|
-
const handleSelectSplitButton = (value) => {
|
86
|
-
selectedTimeFrame.value = value
|
87
|
-
}
|
88
|
-
|
89
|
-
const monthlyData = [
|
90
|
-
{ label: 'Jan', value: 300 },
|
91
|
-
{ label: 'Feb', value: 600 },
|
92
|
-
{ label: 'Mar', value: 1000 },
|
93
|
-
{ label: 'Apr', value: 1200 },
|
94
|
-
{ label: 'May', value: 1400 },
|
95
|
-
{ label: 'Jun', value: 1810 },
|
96
|
-
{ label: 'Jul', value: 1400 },
|
97
|
-
{ label: 'Aug', value: 1200 },
|
98
|
-
{ label: 'Sep', value: 1000 },
|
99
|
-
// { label: 'Oct', value: 800 },
|
100
|
-
// { label: 'Nov', value: 600 },
|
101
|
-
// { label: 'Dec', value: 400 },
|
102
|
-
// { label: 'Jan', value: 300 },
|
103
|
-
// { label: 'Feb', value: 600 },
|
104
|
-
// { label: 'Mar', value: 1000 },
|
105
|
-
// { label: 'Apr', value: 1200 },
|
106
|
-
// { label: 'May', value: 1400 },
|
107
|
-
// { label: 'Jun', value: 1810 },
|
108
|
-
// { label: 'Jul', value: 1400 },
|
109
|
-
// { label: 'Aug', value: 1200 },
|
110
|
-
// { label: 'Sep', value: 1000 },
|
111
|
-
// { label: 'Oct', value: 800 },
|
112
|
-
// { label: 'Nov', value: 600 },
|
113
|
-
// { label: 'Dec', value: 400 },
|
114
|
-
|
115
|
-
// ... more months
|
116
|
-
]
|
117
|
-
|
118
|
-
const monthLabels = [
|
119
|
-
{ label: 'Jan' },
|
120
|
-
{ label: 'Feb' },
|
121
|
-
{ label: 'Mar' },
|
122
|
-
{ label: 'Apr' },
|
123
|
-
{ label: 'May' },
|
124
|
-
{ label: 'Jun' },
|
125
|
-
// ... more months
|
126
|
-
]
|
127
|
-
|
128
|
-
const tariffZones = ref([
|
129
|
-
{
|
130
|
-
name: 'Tariff Zone 1',
|
131
|
-
data: [
|
132
|
-
{ label: 'Jan', value: 200 },
|
133
|
-
{ label: 'Feb', value: 130 },
|
134
|
-
{ label: 'Mar', value: 220 },
|
135
|
-
{ label: 'Apr', value: 230 },
|
136
|
-
{ label: 'May', value: 200 },
|
137
|
-
{ label: 'Jun', value: 210 },
|
138
|
-
// ... more months
|
139
|
-
],
|
140
|
-
},
|
141
|
-
{
|
142
|
-
name: 'Tariff Zone 2',
|
143
|
-
data: [
|
144
|
-
{ label: 'Jan', value: 200 },
|
145
|
-
{ label: 'Feb', value: 100 },
|
146
|
-
{ label: 'Mar', value: 270 },
|
147
|
-
{ label: 'Apr', value: 180 },
|
148
|
-
{ label: 'May', value: 300 },
|
149
|
-
{ label: 'Jun', value: 250 },
|
150
|
-
// ... more months
|
151
|
-
],
|
152
|
-
},
|
153
|
-
{
|
154
|
-
name: 'Tariff Zone 3',
|
155
|
-
data: [
|
156
|
-
{ label: 'Jan', value: 200 },
|
157
|
-
{ label: 'Feb', value: 100 },
|
158
|
-
{ label: 'Mar', value: 210 },
|
159
|
-
{ label: 'Apr', value: 220 },
|
160
|
-
{ label: 'May', value: 300 },
|
161
|
-
{ label: 'Jun', value: 190 },
|
162
|
-
// ... more months
|
163
|
-
],
|
164
|
-
},
|
165
|
-
{
|
166
|
-
name: 'Tariff Zone 4',
|
167
|
-
data: [
|
168
|
-
{ label: 'Jan', value: 200 },
|
169
|
-
{ label: 'Feb', value: 100 },
|
170
|
-
{ label: 'Mar', value: 210 },
|
171
|
-
{ label: 'Apr', value: 220 },
|
172
|
-
{ label: 'May', value: 300 },
|
173
|
-
{ label: 'Jun', value: 190 },
|
174
|
-
// ... more months
|
175
|
-
],
|
176
|
-
},
|
177
|
-
{
|
178
|
-
name: 'Tariff Zone 5',
|
179
|
-
data: [
|
180
|
-
{ label: 'Jan', value: 200 },
|
181
|
-
{ label: 'Feb', value: 100 },
|
182
|
-
{ label: 'Mar', value: 210 },
|
183
|
-
{ label: 'Apr', value: 220 },
|
184
|
-
{ label: 'May', value: 300 },
|
185
|
-
{ label: 'Jun', value: 190 },
|
186
|
-
// ... more months
|
187
|
-
],
|
188
|
-
},
|
189
|
-
{
|
190
|
-
name: 'Tariff Zone 6',
|
191
|
-
data: [
|
192
|
-
{ label: 'Jan', value: 200 },
|
193
|
-
{ label: 'Feb', value: 100 },
|
194
|
-
{ label: 'Mar', value: 210 },
|
195
|
-
{ label: 'Apr', value: 220 },
|
196
|
-
{ label: 'May', value: 300 },
|
197
|
-
{ label: 'Jun', value: 190 },
|
198
|
-
// ... more months
|
199
|
-
],
|
200
|
-
},
|
201
|
-
// ... more tariff zones
|
202
|
-
])
|
203
|
-
|
204
|
-
const valueFormatter = (value) => {
|
205
|
-
return `${value} kWh`
|
206
|
-
}
|
207
|
-
|
208
|
-
const handleSelectionChange = (selectedBars) => {
|
209
|
-
console.log('selectedBars', selectedBars)
|
210
|
-
}
|
211
|
-
|
212
|
-
const handleInputBlur = (payload) => {
|
213
|
-
const newVal = [...tariffZones.value].map((zone) => {
|
214
|
-
if (zone.name === payload.seriesName) {
|
215
|
-
zone.data = zone.data.map((item) => {
|
216
|
-
if (item.label === payload.label) {
|
217
|
-
item.value = payload.value
|
218
|
-
}
|
219
|
-
return item
|
220
|
-
})
|
221
|
-
}
|
222
|
-
return zone
|
223
|
-
})
|
224
|
-
|
225
|
-
tariffZones.value = newVal
|
226
|
-
}
|
227
|
-
</script>
|
228
|
-
|
229
|
-
<style lang="scss" scoped></style>
|