@eturnity/eturnity_reusable_components 8.16.9-EPDM-11600.8 → 8.16.9-EPDM-14690.5
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/TestChart.vue +229 -0
- package/src/assets/svgIcons/erase.svg +3 -2
- package/src/assets/theme.js +1 -1
- package/src/components/barchart/BottomFields.vue +125 -37
- 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 +28 -3
- package/src/components/barchart/index.vue +54 -16
- package/src/components/barchart/styles/bottomFields.js +18 -4
- package/src/components/barchart/styles/chart.js +15 -12
- package/src/components/errorMessage/index.vue +1 -1
- package/src/components/infoCard/index.vue +18 -10
- package/src/components/infoCard/infoCard.spec.js +3 -3
- package/src/components/infoText/index.vue +36 -31
- package/src/components/inputs/inputNumber/InputNumber.stories.js +5 -19
- package/src/components/inputs/inputNumber/index.vue +74 -57
- package/src/components/pageSubtitle/index.vue +1 -7
- package/src/components/pageTitle/index.vue +3 -4
package/package.json
CHANGED
@@ -0,0 +1,229 @@
|
|
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>
|
@@ -1,3 +1,4 @@
|
|
1
|
-
<svg
|
2
|
-
|
1
|
+
<svg fill="none" height="16" viewbox="12 12 16 16" width="16" xmlns="http://www.w3.org/2000/svg">
|
2
|
+
<circle cx="20" cy="20" r="7"></circle>
|
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>
|
3
4
|
</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.
|
336
|
+
backgroundColor: semanticColors.blue[100],
|
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 seriesData" :key="series.name">
|
5
5
|
{{ series.name }}
|
6
6
|
</LabelRow>
|
7
|
-
<TotalRow v-if="
|
8
|
-
{{ $gettext ? $gettext('Total (%)
|
7
|
+
<TotalRow v-if="seriesData.length && fieldMode === 'percentage'">
|
8
|
+
{{ $gettext ? `${$gettext('Total')} (%)` : 'Total (%)' }}
|
9
9
|
</TotalRow>
|
10
|
-
<TotalRow v-if="
|
11
|
-
{{ $gettext ? $gettext('Total (kWh)
|
10
|
+
<TotalRow v-if="seriesData.length">
|
11
|
+
{{ $gettext ? `${$gettext('Total')} (kWh)` : 'Total (kWh)' }}
|
12
12
|
</TotalRow>
|
13
13
|
</LabelsColumn>
|
14
14
|
|
@@ -18,27 +18,35 @@
|
|
18
18
|
>
|
19
19
|
<FieldsWrapper>
|
20
20
|
<!-- For stacked bar chart -->
|
21
|
-
<template v-if="
|
21
|
+
<template v-if="seriesData.length">
|
22
22
|
<InputRow
|
23
|
-
v-for="series in
|
23
|
+
v-for="series in seriesData"
|
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"
|
29
30
|
:bar-width="barWidth"
|
30
31
|
:is-scrollable="isScrollable"
|
31
|
-
:key="index"
|
32
32
|
>
|
33
33
|
<InputNumber
|
34
34
|
:allow-negative="false"
|
35
|
+
:disabled="isInputsDisabled"
|
35
36
|
input-height="36px"
|
36
|
-
:
|
37
|
+
:is-info-border="
|
38
|
+
fieldMode === 'percentage'
|
39
|
+
? calculatePercentageTotal(item.label) !== 100
|
40
|
+
: false
|
41
|
+
"
|
37
42
|
:min-decimals="0"
|
43
|
+
:number-precision="fieldMode === 'percentage' ? 2 : 0"
|
38
44
|
text-align="center"
|
39
45
|
:unit-name="fieldMode === 'percentage' ? '%' : ''"
|
40
46
|
:value="getDisplayValue(series.data, item.label)"
|
41
|
-
@input-blur="
|
47
|
+
@input-blur="
|
48
|
+
handleInputBlur($event, series.name, item.label, series.data)
|
49
|
+
"
|
42
50
|
@input-focus="handleInputFocus(series.name, item.label)"
|
43
51
|
/>
|
44
52
|
</InputGroup>
|
@@ -47,16 +55,17 @@
|
|
47
55
|
<TotalInputRow v-if="fieldMode === 'percentage'">
|
48
56
|
<InputGroup
|
49
57
|
v-for="(item, index) in props.data"
|
58
|
+
:key="index"
|
50
59
|
:bar-width="barWidth"
|
51
60
|
:is-scrollable="isScrollable"
|
52
|
-
:key="index"
|
53
61
|
>
|
54
62
|
<InputNumber
|
55
63
|
:allow-negative="false"
|
64
|
+
:disabled="isInputsDisabled"
|
56
65
|
input-height="36px"
|
57
66
|
:is-read-only="true"
|
58
|
-
:number-precision="0"
|
59
67
|
:min-decimals="0"
|
68
|
+
:number-precision="fieldMode === 'percentage' ? 2 : 0"
|
60
69
|
text-align="center"
|
61
70
|
:unit-name="fieldMode === 'percentage' ? '%' : ''"
|
62
71
|
:value="calculatePercentageTotal(item.label)"
|
@@ -67,17 +76,23 @@
|
|
67
76
|
<TotalInputRow>
|
68
77
|
<InputGroup
|
69
78
|
v-for="(item, index) in props.data"
|
79
|
+
:key="index"
|
70
80
|
:bar-width="barWidth"
|
71
81
|
:is-scrollable="isScrollable"
|
72
|
-
:key="index"
|
73
82
|
>
|
74
83
|
<InputNumber
|
75
84
|
input-height="36px"
|
85
|
+
:is-border-error-only="true"
|
86
|
+
:is-info-border="
|
87
|
+
fieldMode === 'percentage'
|
88
|
+
? calculatePercentageTotal(item.label) !== 100
|
89
|
+
: false
|
90
|
+
"
|
76
91
|
:is-read-only="true"
|
77
|
-
:number-precision="2"
|
78
92
|
:min-decimals="0"
|
93
|
+
:number-precision="0"
|
79
94
|
text-align="center"
|
80
|
-
:value="
|
95
|
+
:value="calculateTotalValue(item.label)"
|
81
96
|
/>
|
82
97
|
</InputGroup>
|
83
98
|
</TotalInputRow>
|
@@ -88,17 +103,19 @@
|
|
88
103
|
<InputRow>
|
89
104
|
<InputGroup
|
90
105
|
v-for="(item, index) in props.data"
|
106
|
+
:key="index"
|
91
107
|
:bar-width="barWidth"
|
92
108
|
:is-scrollable="isScrollable"
|
93
|
-
:key="index"
|
94
109
|
>
|
95
110
|
<InputNumber
|
111
|
+
:allow-negative="false"
|
112
|
+
:disabled="isInputsDisabled"
|
96
113
|
input-height="36px"
|
97
114
|
:min-decimals="0"
|
98
|
-
:number-precision="
|
115
|
+
:number-precision="0"
|
99
116
|
text-align="center"
|
100
117
|
:value="item.value"
|
101
|
-
@input-blur="handleInputBlur($event, null, item.label)"
|
118
|
+
@input-blur="handleInputBlur($event, null, item.label, null)"
|
102
119
|
@input-focus="handleInputFocus(null, item.label)"
|
103
120
|
/>
|
104
121
|
</InputGroup>
|
@@ -107,11 +124,22 @@
|
|
107
124
|
</FieldsWrapper>
|
108
125
|
</FieldsContainer>
|
109
126
|
</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>
|
110
137
|
</template>
|
111
138
|
|
112
139
|
<script setup>
|
113
|
-
import { ref } from 'vue'
|
140
|
+
import { ref, computed, watchEffect } from 'vue'
|
114
141
|
import InputNumber from '../inputs/inputNumber'
|
142
|
+
import InfoCard from '../infoCard'
|
115
143
|
|
116
144
|
import {
|
117
145
|
Container,
|
@@ -123,6 +151,8 @@
|
|
123
151
|
InputRow,
|
124
152
|
TotalInputRow,
|
125
153
|
InputGroup,
|
154
|
+
InfoCardContainer,
|
155
|
+
InfoCardBody,
|
126
156
|
} from './styles/bottomFields'
|
127
157
|
|
128
158
|
const props = defineProps({
|
@@ -159,6 +189,47 @@
|
|
159
189
|
default: 'absolute',
|
160
190
|
validator: (value) => ['absolute', 'percentage'].includes(value),
|
161
191
|
},
|
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]
|
162
233
|
})
|
163
234
|
|
164
235
|
const emit = defineEmits([
|
@@ -175,11 +246,13 @@
|
|
175
246
|
emit('input-focus', { seriesName, label })
|
176
247
|
}
|
177
248
|
|
178
|
-
const
|
179
|
-
|
249
|
+
const calculateTotalValue = (label) => {
|
250
|
+
const total = seriesData.value.reduce((sum, series) => {
|
180
251
|
const value = series.data.find((d) => d.label === label)?.value || 0
|
181
252
|
return sum + value
|
182
253
|
}, 0)
|
254
|
+
|
255
|
+
return Math.round(total)
|
183
256
|
}
|
184
257
|
|
185
258
|
const syncScroll = (scrollLeft) => {
|
@@ -190,34 +263,43 @@
|
|
190
263
|
container.scrollLeft = scrollLeft
|
191
264
|
}
|
192
265
|
}
|
193
|
-
|
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) => {
|
194
276
|
if (props.fieldMode === 'absolute') {
|
195
|
-
return
|
277
|
+
return data.find((d) => d.label === label)?.value
|
196
278
|
}
|
197
279
|
|
198
|
-
|
199
|
-
const total = calculateTotal(label)
|
200
|
-
return total ? Number(((value / total) * 100).toFixed(0)) : 0
|
280
|
+
return data.find((d) => d.label === label)?.percentage
|
201
281
|
}
|
202
282
|
|
203
283
|
const calculatePercentageTotal = (label) => {
|
204
|
-
|
205
|
-
const
|
206
|
-
|
207
|
-
const percentage = total ? Number(((value / total) * 100).toFixed(0)) : 0
|
284
|
+
const percentageTotal = seriesData.value.reduce((sum, series) => {
|
285
|
+
const percentage =
|
286
|
+
series.data.find((d) => d.label === label)?.percentage || 0
|
208
287
|
return sum + percentage
|
209
288
|
}, 0)
|
289
|
+
|
290
|
+
return Math.round(percentageTotal)
|
210
291
|
}
|
211
292
|
|
212
|
-
const handleInputBlur = (_value, seriesName, label) => {
|
293
|
+
const handleInputBlur = (_value, seriesName, label, currentSeriesData) => {
|
213
294
|
let value = Number(_value)
|
214
295
|
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
296
|
+
const payload = seriesName
|
297
|
+
? {
|
298
|
+
seriesName,
|
299
|
+
label,
|
300
|
+
value,
|
301
|
+
}
|
302
|
+
: { label, value }
|
221
303
|
emit('input-blur', payload)
|
222
304
|
focusedInput.value = null
|
223
305
|
|
@@ -243,6 +325,12 @@
|
|
243
325
|
}
|
244
326
|
}
|
245
327
|
|
328
|
+
const hasAnySegmentNotTotatTo100Percent = computed(() => {
|
329
|
+
return props.data.some((d) => {
|
330
|
+
return calculatePercentageTotal(d.label) !== 100
|
331
|
+
})
|
332
|
+
})
|
333
|
+
|
246
334
|
const handleFieldsScroll = (event) => {
|
247
335
|
emit('sync-scroll', event.target.scrollLeft)
|
248
336
|
}
|
@@ -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 ? '80px' : '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].
|
69
|
+
segments: [...props.series].map((series, index) => {
|
70
70
|
const value =
|
71
71
|
series.data.find((d) => d.label === item.label)?.value || 0
|
72
72
|
accumulated += value
|
@@ -16,7 +16,21 @@ export function useTooltip(chartId, normalizedData) {
|
|
16
16
|
if (!showTooltipContent.value) {
|
17
17
|
showTooltipContent.value = true
|
18
18
|
}
|
19
|
-
if (isObjectEqual(item, tooltipData.value))
|
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
|
20
34
|
|
21
35
|
tooltipData.value = { ...item }
|
22
36
|
|
@@ -41,16 +55,27 @@ export function useTooltip(chartId, normalizedData) {
|
|
41
55
|
|
42
56
|
isInputFocused.value = true
|
43
57
|
const barData = normalizedData.value.find((item) => item.label === label)
|
44
|
-
|
45
58
|
if (!barData) return
|
59
|
+
|
60
|
+
const totalValue = barData.segments.reduce((acc, segment) => {
|
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
|
46
70
|
focusedBarData.value = barData
|
71
|
+
|
47
72
|
const barElement = document.querySelector(
|
48
73
|
`.barchart-${chartId} .bar-group:nth-child(${
|
49
74
|
normalizedData.value.indexOf(barData) + 1
|
50
75
|
})`
|
51
76
|
)
|
52
|
-
|
53
77
|
if (!barElement) return
|
78
|
+
|
54
79
|
// Get the last bar segment, samee as hover behavior
|
55
80
|
const targetElement = barElement.querySelector('.bar-segment:last-child')
|
56
81
|
const rect = targetElement.getBoundingClientRect()
|