@dative-gpi/foundation-shared-components 1.0.159 → 1.0.161-alert-tile
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/components/FSInstantPicker.vue +36 -51
- package/components/FSOptionsMenu.vue +165 -0
- package/components/FSRangePicker.vue +261 -0
- package/components/FSRangeSlider.vue +84 -0
- package/components/FSSlider.vue +41 -77
- package/components/FSTagGroup.vue +3 -1
- package/components/lists/FSDataTableUI.vue +16 -11
- package/components/map/FSMap.vue +1 -1
- package/components/tiles/FSEntityCountBadge.vue +72 -0
- package/components/tiles/FSFolderTileUI.vue +38 -4
- package/components/tiles/FSGroupTileUI.vue +15 -67
- package/components/tiles/FSLocationTileUI.vue +9 -28
- package/components/views/mobile/FSBaseDefaultMobileView.vue +2 -2
- package/composables/useMapLayers.ts +60 -53
- package/package.json +4 -4
- package/styles/components/fs_slider.scss +0 -40
- package/tools/alertsTools.ts +11 -10
- package/tools/chartsTools.ts +13 -1
- package/utils/index.ts +1 -0
- package/utils/picker.ts +40 -0
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
:required="$props.required"
|
|
6
6
|
:disabled="$props.disabled"
|
|
7
7
|
:label="$props.label"
|
|
8
|
+
:maxWidth="$props.maxWidth"
|
|
8
9
|
>
|
|
9
10
|
<FSRow
|
|
10
11
|
align="bottom-center"
|
|
@@ -23,15 +24,12 @@
|
|
|
23
24
|
padding="0 0 2px 0"
|
|
24
25
|
align="center-center"
|
|
25
26
|
>
|
|
26
|
-
<FSCol
|
|
27
|
-
width="fill"
|
|
28
|
-
>
|
|
27
|
+
<FSCol>
|
|
29
28
|
<FSSlider
|
|
30
29
|
minWidth='min(300px, 90vw)'
|
|
31
30
|
:disabled="$props.disabled"
|
|
32
31
|
:color="ColorEnum.Light"
|
|
33
32
|
:thumbColor="ColorEnum.Primary"
|
|
34
|
-
:thumbSize="18"
|
|
35
33
|
:trackSize="8"
|
|
36
34
|
thumb-label="always"
|
|
37
35
|
:step="$props.stepTime"
|
|
@@ -52,20 +50,14 @@
|
|
|
52
50
|
</FSSpan>
|
|
53
51
|
</template>
|
|
54
52
|
<template
|
|
55
|
-
#tick-label="{ tick
|
|
53
|
+
#tick-label="{ tick }"
|
|
56
54
|
>
|
|
57
|
-
<FSRow
|
|
58
|
-
v-if="index % Math.trunc(ticks.length / maximumTickToShow) === 0 || ticks.length < maximumTickToShow"
|
|
59
|
-
>
|
|
55
|
+
<FSRow>
|
|
60
56
|
<FSText
|
|
61
57
|
:color="lightColors.dark"
|
|
62
58
|
font="text-overline"
|
|
63
59
|
>
|
|
64
|
-
{{
|
|
65
|
-
?
|
|
66
|
-
epochToShortTimeOnlyFormat(tick.value)
|
|
67
|
-
:
|
|
68
|
-
epochToDayMonthShortOnly(tick.value)
|
|
60
|
+
{{ tickPrecision === TimePrecision.Hours ? epochToShortTimeOnlyFormat(tick.value) : epochToDayMonthShortOnly(tick.value)
|
|
69
61
|
}}
|
|
70
62
|
</FSText>
|
|
71
63
|
</FSRow>
|
|
@@ -88,18 +80,19 @@
|
|
|
88
80
|
<script lang="ts">
|
|
89
81
|
import { computed, defineComponent, ref, watch } from "vue";
|
|
90
82
|
|
|
83
|
+
import { useBreakpoints, useColors } from '@dative-gpi/foundation-shared-components/composables';
|
|
91
84
|
import { useDateFormat, useDateExpression } from "@dative-gpi/foundation-shared-services/composables";
|
|
92
85
|
|
|
93
86
|
import { ColorEnum } from "@dative-gpi/foundation-shared-components/models";
|
|
94
|
-
import {
|
|
87
|
+
import { computeTicks, TimePrecision } from '@dative-gpi/foundation-shared-components/utils';
|
|
95
88
|
|
|
96
89
|
import FSCol from '@dative-gpi/foundation-shared-components/components/FSCol.vue';
|
|
97
90
|
import FSSpan from '@dative-gpi/foundation-shared-components/components/FSSpan.vue';
|
|
98
91
|
import FSText from '@dative-gpi/foundation-shared-components/components/FSText.vue';
|
|
99
92
|
import FSSlider from '@dative-gpi/foundation-shared-components/components/FSSlider.vue';
|
|
93
|
+
import FSPlayButtons from '@dative-gpi/foundation-shared-components/components/FSPlayButtons.vue';
|
|
100
94
|
import FSBaseField from '@dative-gpi/foundation-shared-components/components/fields/FSBaseField.vue';
|
|
101
95
|
import FSTermField from '@dative-gpi/foundation-shared-components/components/fields/FSTermField.vue';
|
|
102
|
-
import FSPlayButtons from '@dative-gpi/foundation-shared-components/components/FSPlayButtons.vue';
|
|
103
96
|
|
|
104
97
|
export default defineComponent({
|
|
105
98
|
name: "FSInstantPicker",
|
|
@@ -110,7 +103,7 @@ export default defineComponent({
|
|
|
110
103
|
FSSlider,
|
|
111
104
|
FSTermField,
|
|
112
105
|
FSBaseField,
|
|
113
|
-
FSPlayButtons
|
|
106
|
+
FSPlayButtons,
|
|
114
107
|
},
|
|
115
108
|
props: {
|
|
116
109
|
label: {
|
|
@@ -119,8 +112,7 @@ export default defineComponent({
|
|
|
119
112
|
},
|
|
120
113
|
modelValue: {
|
|
121
114
|
type: Number,
|
|
122
|
-
required: false
|
|
123
|
-
default: 0,
|
|
115
|
+
required: false
|
|
124
116
|
},
|
|
125
117
|
startDate: {
|
|
126
118
|
type: String,
|
|
@@ -164,6 +156,11 @@ export default defineComponent({
|
|
|
164
156
|
type: Number,
|
|
165
157
|
required: false,
|
|
166
158
|
default: 50
|
|
159
|
+
},
|
|
160
|
+
maxWidth: {
|
|
161
|
+
type: String as PropType<string | null>,
|
|
162
|
+
required: false,
|
|
163
|
+
default: null
|
|
167
164
|
}
|
|
168
165
|
},
|
|
169
166
|
emits: ['update:modelValue', 'update:startDate', 'update:endDate'],
|
|
@@ -180,38 +177,26 @@ export default defineComponent({
|
|
|
180
177
|
const startTimestamp = computed(() => convertTermToEpoch(props.startDate));
|
|
181
178
|
const endTimestamp = computed(() => convertTermToEpoch(props.endDate));
|
|
182
179
|
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
return (endTimestamp.value - startTimestamp.value) / interval < 100;
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
if (interval) {
|
|
191
|
-
return interval;
|
|
192
|
-
}
|
|
193
|
-
return 86400000;
|
|
180
|
+
const tickCount = computed(() => {
|
|
181
|
+
if (isExtraSmall.value) { return 3; }
|
|
182
|
+
if (isMobileSized.value) { return 4; }
|
|
183
|
+
return 5;
|
|
194
184
|
});
|
|
195
185
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
}
|
|
203
|
-
return ticks;
|
|
186
|
+
// Pour la précision, on peut rester sur l'heure ou le jour selon la plage
|
|
187
|
+
const tickPrecision = computed(() => {
|
|
188
|
+
const rangeDuration = endTimestamp.value - startTimestamp.value;
|
|
189
|
+
if (rangeDuration <= 86400000 * tickCount.value) { return TimePrecision.Hours; }
|
|
190
|
+
if (rangeDuration <= 2592000000 * tickCount.value) { return TimePrecision.Days; }
|
|
191
|
+
return TimePrecision.Months;
|
|
204
192
|
});
|
|
205
193
|
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}
|
|
213
|
-
return 6;
|
|
214
|
-
});
|
|
194
|
+
const ticks = computed(() => computeTicks({
|
|
195
|
+
start: startTimestamp.value,
|
|
196
|
+
end: endTimestamp.value,
|
|
197
|
+
tickCount: tickCount.value,
|
|
198
|
+
precision: tickPrecision.value
|
|
199
|
+
}));
|
|
215
200
|
|
|
216
201
|
const onPlayingChange = (value: boolean) => {
|
|
217
202
|
playing.value = value;
|
|
@@ -225,8 +210,8 @@ export default defineComponent({
|
|
|
225
210
|
emit('update:modelValue', endTimestamp.value);
|
|
226
211
|
};
|
|
227
212
|
|
|
228
|
-
watch(() =>
|
|
229
|
-
if(props.modelValue < startTimestamp.value || props.modelValue > endTimestamp.value) {
|
|
213
|
+
watch([() => props.startDate, () => props.endDate, () => props.modelValue], () => {
|
|
214
|
+
if(!props.modelValue || props.modelValue < startTimestamp.value || props.modelValue > endTimestamp.value) {
|
|
230
215
|
emit('update:modelValue', endTimestamp.value);
|
|
231
216
|
}
|
|
232
217
|
}, { immediate: true });
|
|
@@ -236,7 +221,7 @@ export default defineComponent({
|
|
|
236
221
|
clearInterval(playingInterval.value);
|
|
237
222
|
} else {
|
|
238
223
|
playingInterval.value = setInterval(() => {
|
|
239
|
-
if(props.modelValue + props.stepTime <= endTimestamp.value) {
|
|
224
|
+
if(props.modelValue && props.modelValue + props.stepTime <= endTimestamp.value) {
|
|
240
225
|
emit('update:modelValue', props.modelValue + props.stepTime);
|
|
241
226
|
} else {
|
|
242
227
|
emit('update:modelValue', endTimestamp.value);
|
|
@@ -251,10 +236,10 @@ export default defineComponent({
|
|
|
251
236
|
playing,
|
|
252
237
|
ColorEnum,
|
|
253
238
|
lightColors,
|
|
254
|
-
intervalTime,
|
|
255
239
|
endTimestamp,
|
|
240
|
+
TimePrecision,
|
|
241
|
+
tickPrecision,
|
|
256
242
|
startTimestamp,
|
|
257
|
-
maximumTickToShow,
|
|
258
243
|
epochToISO,
|
|
259
244
|
onPlayingChange,
|
|
260
245
|
onClickForward,
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<FSMenu
|
|
3
|
+
:location="$props.location"
|
|
4
|
+
:closeOnContentClick="true"
|
|
5
|
+
:contained="false"
|
|
6
|
+
minWidth="0"
|
|
7
|
+
v-model="modelValue"
|
|
8
|
+
v-bind="$attrs"
|
|
9
|
+
>
|
|
10
|
+
<template
|
|
11
|
+
#activator="{ props }"
|
|
12
|
+
>
|
|
13
|
+
<slot
|
|
14
|
+
name="activator"
|
|
15
|
+
v-bind="props"
|
|
16
|
+
>
|
|
17
|
+
<FSButton
|
|
18
|
+
v-bind="props"
|
|
19
|
+
:icon="$props.icon"
|
|
20
|
+
:iconSize="$props.iconSize"
|
|
21
|
+
:color="$props.buttonColor"
|
|
22
|
+
:variant="$props.buttonVariant"
|
|
23
|
+
/>
|
|
24
|
+
</slot>
|
|
25
|
+
</template>
|
|
26
|
+
<FSCard
|
|
27
|
+
:maxWidth="$props.maxWidth"
|
|
28
|
+
:width="$props.width"
|
|
29
|
+
padding="2px"
|
|
30
|
+
:border="false"
|
|
31
|
+
:elevation="true"
|
|
32
|
+
align="center-center"
|
|
33
|
+
>
|
|
34
|
+
<slot
|
|
35
|
+
name="content"
|
|
36
|
+
>
|
|
37
|
+
<FSCol
|
|
38
|
+
gap="0px"
|
|
39
|
+
>
|
|
40
|
+
<FSFadeOut
|
|
41
|
+
:scrollOutside="false"
|
|
42
|
+
maxHeight="80dvh"
|
|
43
|
+
>
|
|
44
|
+
<FSClickable
|
|
45
|
+
v-for="(item, index) in $props.items"
|
|
46
|
+
width="100%"
|
|
47
|
+
padding="8px"
|
|
48
|
+
height="40px"
|
|
49
|
+
:key="index"
|
|
50
|
+
:border="false"
|
|
51
|
+
@click="onClickItem(item)"
|
|
52
|
+
>
|
|
53
|
+
<slot
|
|
54
|
+
name="item"
|
|
55
|
+
v-bind="{ item, index }"
|
|
56
|
+
>
|
|
57
|
+
<FSRow
|
|
58
|
+
align="center-left"
|
|
59
|
+
>
|
|
60
|
+
<FSIcon
|
|
61
|
+
v-if="item.icon"
|
|
62
|
+
:icon="item.icon"
|
|
63
|
+
/>
|
|
64
|
+
<FSText
|
|
65
|
+
font="text-body"
|
|
66
|
+
>
|
|
67
|
+
{{ item.label }}
|
|
68
|
+
</FSText>
|
|
69
|
+
</FSRow>
|
|
70
|
+
</slot>
|
|
71
|
+
</FSClickable>
|
|
72
|
+
</FSFadeOut>
|
|
73
|
+
</FSCol>
|
|
74
|
+
</slot>
|
|
75
|
+
</FSCard>
|
|
76
|
+
</FSMenu>
|
|
77
|
+
</template>
|
|
78
|
+
|
|
79
|
+
<script lang="ts">
|
|
80
|
+
import { defineComponent, ref, type PropType } from "vue";
|
|
81
|
+
|
|
82
|
+
import { useColors } from "@dative-gpi/foundation-shared-components/composables";
|
|
83
|
+
|
|
84
|
+
import { ColorEnum, type ColorBase } from '@dative-gpi/foundation-shared-components/models';
|
|
85
|
+
|
|
86
|
+
import FSRow from '@dative-gpi/foundation-shared-components/components/FSRow.vue';
|
|
87
|
+
import FSCol from '@dative-gpi/foundation-shared-components/components/FSCol.vue';
|
|
88
|
+
import FSIcon from '@dative-gpi/foundation-shared-components/components/FSIcon.vue';
|
|
89
|
+
import FSMenu from '@dative-gpi/foundation-shared-components/components/FSMenu.vue';
|
|
90
|
+
import FSCard from '@dative-gpi/foundation-shared-components/components/FSCard.vue';
|
|
91
|
+
import FSText from '@dative-gpi/foundation-shared-components/components/FSText.vue';
|
|
92
|
+
import FSButton from '@dative-gpi/foundation-shared-components/components/FSButton.vue';
|
|
93
|
+
import FSClickable from '@dative-gpi/foundation-shared-components/components/FSClickable.vue';
|
|
94
|
+
|
|
95
|
+
export default defineComponent({
|
|
96
|
+
name: "FSInformationsMenu",
|
|
97
|
+
components: {
|
|
98
|
+
FSMenu,
|
|
99
|
+
FSCard,
|
|
100
|
+
FSRow,
|
|
101
|
+
FSText,
|
|
102
|
+
FSButton,
|
|
103
|
+
FSCol,
|
|
104
|
+
FSIcon,
|
|
105
|
+
FSClickable
|
|
106
|
+
},
|
|
107
|
+
props: {
|
|
108
|
+
items: {
|
|
109
|
+
type: Array as PropType<{label: string, icon?: string, onClick: () => void, closeOnContentClick?: boolean}[]>,
|
|
110
|
+
default: () => []
|
|
111
|
+
},
|
|
112
|
+
location: {
|
|
113
|
+
type: String,
|
|
114
|
+
default: "bottom"
|
|
115
|
+
},
|
|
116
|
+
width: {
|
|
117
|
+
type: [Array, String, Number] as PropType<string[] | number[] | string | number | null>,
|
|
118
|
+
default: null
|
|
119
|
+
},
|
|
120
|
+
maxWidth: {
|
|
121
|
+
type: [Array, String, Number] as PropType<string[] | number[] | string | number | null>,
|
|
122
|
+
default: "90dvw"
|
|
123
|
+
},
|
|
124
|
+
icon: {
|
|
125
|
+
type: String,
|
|
126
|
+
default: "mdi-dots-horizontal"
|
|
127
|
+
},
|
|
128
|
+
iconSize: {
|
|
129
|
+
type: String,
|
|
130
|
+
default: "18px"
|
|
131
|
+
},
|
|
132
|
+
buttonColor: {
|
|
133
|
+
type: String as PropType<ColorBase>,
|
|
134
|
+
default: ColorEnum.Light
|
|
135
|
+
},
|
|
136
|
+
buttonVariant: {
|
|
137
|
+
type: String as PropType<"standard" | "full" | "icon">,
|
|
138
|
+
required: false,
|
|
139
|
+
default: "icon"
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
emits: ["update:modelValue"],
|
|
143
|
+
setup() {
|
|
144
|
+
const modelValue = ref(false);
|
|
145
|
+
|
|
146
|
+
const { getColors } = useColors();
|
|
147
|
+
|
|
148
|
+
const lightColors = getColors(ColorEnum.Light);
|
|
149
|
+
|
|
150
|
+
const onClickItem = (item: { onClick: () => void, closeOnContentClick?: boolean }) => {
|
|
151
|
+
item.onClick();
|
|
152
|
+
if (item.closeOnContentClick !== false) {
|
|
153
|
+
modelValue.value = false;
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
return {
|
|
158
|
+
ColorEnum,
|
|
159
|
+
modelValue,
|
|
160
|
+
lightColors,
|
|
161
|
+
onClickItem
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
</script>
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<FSBaseField
|
|
3
|
+
:description="$props.description"
|
|
4
|
+
:hideHeader="$props.hideHeader"
|
|
5
|
+
:required="$props.required"
|
|
6
|
+
:disabled="$props.disabled"
|
|
7
|
+
:label="$props.label"
|
|
8
|
+
:maxWidth="$props.maxWidth"
|
|
9
|
+
>
|
|
10
|
+
<FSRow
|
|
11
|
+
align="bottom-center"
|
|
12
|
+
gap="32px"
|
|
13
|
+
>
|
|
14
|
+
<FSTermField
|
|
15
|
+
width="430px"
|
|
16
|
+
:label="$tr('ui.instant-picker.analyze-period', 'Analyze Period')"
|
|
17
|
+
:startDate="$props.startDate"
|
|
18
|
+
:endDate="$props.endDate"
|
|
19
|
+
:disabled="$props.disabled"
|
|
20
|
+
@update:startDate="$emit('update:startDate', $event)"
|
|
21
|
+
@update:endDate="$emit('update:endDate', $event)"
|
|
22
|
+
/>
|
|
23
|
+
<FSRow
|
|
24
|
+
padding="0 0 2px 0"
|
|
25
|
+
align="center-center"
|
|
26
|
+
>
|
|
27
|
+
<FSCol>
|
|
28
|
+
<FSRangeSlider
|
|
29
|
+
minWidth='min(300px, 90vw)'
|
|
30
|
+
:disabled="$props.disabled"
|
|
31
|
+
:color="ColorEnum.Light"
|
|
32
|
+
:thumbColor="ColorEnum.Primary"
|
|
33
|
+
:trackFillColor="ColorEnum.Primary"
|
|
34
|
+
:trackSize="8"
|
|
35
|
+
thumb-label="always"
|
|
36
|
+
:step="$props.stepTime"
|
|
37
|
+
:min="startTimestamp"
|
|
38
|
+
:max="endTimestamp"
|
|
39
|
+
:ticks="ticks"
|
|
40
|
+
showTicks="always"
|
|
41
|
+
:modelValue="$props.modelValue"
|
|
42
|
+
@update:modelValue="$emit('update:modelValue', $event)"
|
|
43
|
+
>
|
|
44
|
+
<template
|
|
45
|
+
#thumb-label="{ modelValue }"
|
|
46
|
+
>
|
|
47
|
+
<FSSpan
|
|
48
|
+
font="text-overline"
|
|
49
|
+
>
|
|
50
|
+
{{ epochToMonthShortTimeFormat(modelValue) }}
|
|
51
|
+
</FSSpan>
|
|
52
|
+
</template>
|
|
53
|
+
<template
|
|
54
|
+
#tick-label="{ tick }"
|
|
55
|
+
>
|
|
56
|
+
<FSRow>
|
|
57
|
+
<FSText
|
|
58
|
+
:color="lightColors.dark"
|
|
59
|
+
font="text-overline"
|
|
60
|
+
>
|
|
61
|
+
{{ tickPrecision === TimePrecision.Hours ? epochToShortTimeOnlyFormat(tick.value) : epochToDayMonthShortOnly(tick.value) }}
|
|
62
|
+
</FSText>
|
|
63
|
+
</FSRow>
|
|
64
|
+
</template>
|
|
65
|
+
</FSRangeSlider>
|
|
66
|
+
</FSCol>
|
|
67
|
+
<FSPlayButtons
|
|
68
|
+
v-if="$props.playable"
|
|
69
|
+
:disabled="$props.disabled"
|
|
70
|
+
:modelValue="playing"
|
|
71
|
+
@click:backward="onClickBackward"
|
|
72
|
+
@click:forward="onClickForward"
|
|
73
|
+
@update:modelValue="onPlayingChange"
|
|
74
|
+
/>
|
|
75
|
+
</FSRow>
|
|
76
|
+
</FSRow>
|
|
77
|
+
</FSBaseField>
|
|
78
|
+
</template>
|
|
79
|
+
|
|
80
|
+
<script lang="ts">
|
|
81
|
+
import { computed, defineComponent, ref, watch, type PropType } from "vue";
|
|
82
|
+
|
|
83
|
+
import { useBreakpoints, useColors } from '@dative-gpi/foundation-shared-components/composables';
|
|
84
|
+
import { useDateFormat, useDateExpression } from "@dative-gpi/foundation-shared-services/composables";
|
|
85
|
+
|
|
86
|
+
import { ColorEnum } from "@dative-gpi/foundation-shared-components/models";
|
|
87
|
+
import { computeTicks, TimePrecision } from '@dative-gpi/foundation-shared-components/utils';
|
|
88
|
+
|
|
89
|
+
import FSCol from '@dative-gpi/foundation-shared-components/components/FSCol.vue';
|
|
90
|
+
import FSSpan from '@dative-gpi/foundation-shared-components/components/FSSpan.vue';
|
|
91
|
+
import FSText from '@dative-gpi/foundation-shared-components/components/FSText.vue';
|
|
92
|
+
import FSPlayButtons from '@dative-gpi/foundation-shared-components/components/FSPlayButtons.vue';
|
|
93
|
+
import FSRangeSlider from '@dative-gpi/foundation-shared-components/components/FSRangeSlider.vue';
|
|
94
|
+
import FSBaseField from '@dative-gpi/foundation-shared-components/components/fields/FSBaseField.vue';
|
|
95
|
+
import FSTermField from '@dative-gpi/foundation-shared-components/components/fields/FSTermField.vue';
|
|
96
|
+
|
|
97
|
+
export default defineComponent({
|
|
98
|
+
name: "FSRangePicker",
|
|
99
|
+
components: {
|
|
100
|
+
FSCol,
|
|
101
|
+
FSSpan,
|
|
102
|
+
FSText,
|
|
103
|
+
FSTermField,
|
|
104
|
+
FSBaseField,
|
|
105
|
+
FSRangeSlider,
|
|
106
|
+
FSPlayButtons,
|
|
107
|
+
},
|
|
108
|
+
props: {
|
|
109
|
+
label: {
|
|
110
|
+
type: String,
|
|
111
|
+
required: false,
|
|
112
|
+
},
|
|
113
|
+
mode: {
|
|
114
|
+
type: String as () => 'single' | 'range',
|
|
115
|
+
required: false,
|
|
116
|
+
default: 'single'
|
|
117
|
+
},
|
|
118
|
+
modelValue: {
|
|
119
|
+
type: Object as () => [number, number],
|
|
120
|
+
required: true
|
|
121
|
+
},
|
|
122
|
+
startDate: {
|
|
123
|
+
type: String,
|
|
124
|
+
required: true
|
|
125
|
+
},
|
|
126
|
+
endDate: {
|
|
127
|
+
type: String,
|
|
128
|
+
required: true
|
|
129
|
+
},
|
|
130
|
+
description: {
|
|
131
|
+
type: String,
|
|
132
|
+
required: false,
|
|
133
|
+
default: null
|
|
134
|
+
},
|
|
135
|
+
hideHeader: {
|
|
136
|
+
type: Boolean,
|
|
137
|
+
required: false,
|
|
138
|
+
default: false
|
|
139
|
+
},
|
|
140
|
+
required: {
|
|
141
|
+
type: Boolean,
|
|
142
|
+
required: false,
|
|
143
|
+
default: false
|
|
144
|
+
},
|
|
145
|
+
disabled: {
|
|
146
|
+
type: Boolean,
|
|
147
|
+
required: false,
|
|
148
|
+
default: false
|
|
149
|
+
},
|
|
150
|
+
playable: {
|
|
151
|
+
type: Boolean,
|
|
152
|
+
required: false,
|
|
153
|
+
default: true
|
|
154
|
+
},
|
|
155
|
+
stepTime: {
|
|
156
|
+
type: Number,
|
|
157
|
+
required: false,
|
|
158
|
+
default: 60000
|
|
159
|
+
},
|
|
160
|
+
playingStepDuration: {
|
|
161
|
+
type: Number,
|
|
162
|
+
required: false,
|
|
163
|
+
default: 50
|
|
164
|
+
},
|
|
165
|
+
maxWidth: {
|
|
166
|
+
type: String as PropType<string | null>,
|
|
167
|
+
required: false,
|
|
168
|
+
default: null
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
emits: ['update:modelValue', 'update:startDate', 'update:endDate'],
|
|
172
|
+
setup(props, { emit }) {
|
|
173
|
+
const { epochToShortTimeOnlyFormat, epochToShortDateFormat, epochToDayMonthShortOnly, epochToISO, epochToMonthShortTimeFormat } = useDateFormat();
|
|
174
|
+
const { convert : convertTermToEpoch } = useDateExpression();
|
|
175
|
+
const { isMobileSized, isExtraSmall } = useBreakpoints();
|
|
176
|
+
const { getColors } = useColors();
|
|
177
|
+
|
|
178
|
+
const lightColors = getColors(ColorEnum.Light);
|
|
179
|
+
const playing = ref(false);
|
|
180
|
+
const playingInterval = ref();
|
|
181
|
+
|
|
182
|
+
const startTimestamp = computed(() => convertTermToEpoch(props.startDate));
|
|
183
|
+
const endTimestamp = computed(() => convertTermToEpoch(props.endDate));
|
|
184
|
+
|
|
185
|
+
const tickCount = computed(() => {
|
|
186
|
+
if (isExtraSmall.value) { return 3; }
|
|
187
|
+
if (isMobileSized.value) { return 4; }
|
|
188
|
+
return 5;
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
const tickPrecision = computed(() => {
|
|
192
|
+
const rangeDuration = endTimestamp.value - startTimestamp.value;
|
|
193
|
+
if (rangeDuration <= 86400000 * tickCount.value) { return TimePrecision.Hours; }
|
|
194
|
+
if (rangeDuration <= 2592000000 * tickCount.value) { return TimePrecision.Days; }
|
|
195
|
+
return TimePrecision.Months;
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// Génération des ticks via la fonction utilitaire
|
|
199
|
+
const ticks = computed(() => computeTicks({
|
|
200
|
+
start: startTimestamp.value,
|
|
201
|
+
end: endTimestamp.value,
|
|
202
|
+
tickCount: tickCount.value,
|
|
203
|
+
precision: tickPrecision.value
|
|
204
|
+
}));
|
|
205
|
+
|
|
206
|
+
const onPlayingChange = (value: boolean) => {
|
|
207
|
+
playing.value = value;
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
const onClickBackward = () => {
|
|
211
|
+
const modelValueDuration = props.modelValue[1] - props.modelValue[0];
|
|
212
|
+
emit('update:modelValue', [startTimestamp.value, startTimestamp.value + modelValueDuration]);
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
const onClickForward = () => {
|
|
216
|
+
const modelValueDuration = props.modelValue[1] - props.modelValue[0];
|
|
217
|
+
emit('update:modelValue', [endTimestamp.value - modelValueDuration, endTimestamp.value]);
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
watch([() => props.startDate, () => props.endDate, () => props.modelValue], () => {
|
|
221
|
+
if((props.modelValue[0] < startTimestamp.value || props.modelValue[1] > endTimestamp.value)) {
|
|
222
|
+
emit('update:modelValue', [startTimestamp.value, endTimestamp.value]);
|
|
223
|
+
}
|
|
224
|
+
}, { immediate: true });
|
|
225
|
+
|
|
226
|
+
watch(playing, (value) => {
|
|
227
|
+
if(!value && playingInterval.value) {
|
|
228
|
+
clearInterval(playingInterval.value);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
playingInterval.value = setInterval(() => {
|
|
233
|
+
if(props.modelValue[0] + props.stepTime <= endTimestamp.value && props.modelValue[1] + props.stepTime <= endTimestamp.value) {
|
|
234
|
+
emit('update:modelValue', [props.modelValue[0] + props.stepTime, props.modelValue[1] + props.stepTime]);
|
|
235
|
+
} else {
|
|
236
|
+
playing.value = false;
|
|
237
|
+
}
|
|
238
|
+
}, props.playingStepDuration);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
return {
|
|
242
|
+
ticks,
|
|
243
|
+
playing,
|
|
244
|
+
ColorEnum,
|
|
245
|
+
lightColors,
|
|
246
|
+
endTimestamp,
|
|
247
|
+
TimePrecision,
|
|
248
|
+
tickPrecision,
|
|
249
|
+
startTimestamp,
|
|
250
|
+
epochToISO,
|
|
251
|
+
onPlayingChange,
|
|
252
|
+
onClickForward,
|
|
253
|
+
onClickBackward,
|
|
254
|
+
epochToShortDateFormat,
|
|
255
|
+
epochToShortTimeOnlyFormat,
|
|
256
|
+
epochToDayMonthShortOnly,
|
|
257
|
+
epochToMonthShortTimeFormat
|
|
258
|
+
};
|
|
259
|
+
},
|
|
260
|
+
});
|
|
261
|
+
</script>
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<FSBaseField
|
|
3
|
+
:label="$props.label"
|
|
4
|
+
:description="$props.description"
|
|
5
|
+
:required="$props.required"
|
|
6
|
+
:disabled="$props.disabled"
|
|
7
|
+
>
|
|
8
|
+
<FSRow>
|
|
9
|
+
<v-range-slider
|
|
10
|
+
hide-details
|
|
11
|
+
width="100%"
|
|
12
|
+
:disabled="$props.disabled"
|
|
13
|
+
:ripple="false"
|
|
14
|
+
:color="$props.color"
|
|
15
|
+
:trackSize="6"
|
|
16
|
+
:elevation="0"
|
|
17
|
+
:tickSize="4"
|
|
18
|
+
:modelValue="$props.modelValue ?? undefined"
|
|
19
|
+
@update:modelValue="$emit('update:modelValue', $event)"
|
|
20
|
+
v-bind="$attrs"
|
|
21
|
+
>
|
|
22
|
+
<template
|
|
23
|
+
v-for="(_, name) in $slots"
|
|
24
|
+
v-slot:[name]="slotData"
|
|
25
|
+
>
|
|
26
|
+
<slot
|
|
27
|
+
:name="name"
|
|
28
|
+
v-bind="slotData"
|
|
29
|
+
/>
|
|
30
|
+
</template>
|
|
31
|
+
</v-range-slider>
|
|
32
|
+
</FSRow>
|
|
33
|
+
</FSBaseField>
|
|
34
|
+
</template>
|
|
35
|
+
|
|
36
|
+
<script lang="ts">
|
|
37
|
+
import { defineComponent, type PropType } from "vue";
|
|
38
|
+
|
|
39
|
+
import { type ColorBase, ColorEnum } from "@dative-gpi/foundation-shared-components/models";
|
|
40
|
+
|
|
41
|
+
import FSRow from '@dative-gpi/foundation-shared-components/components/FSRow.vue';
|
|
42
|
+
import FSBaseField from '@dative-gpi/foundation-shared-components/components/fields/FSBaseField.vue';
|
|
43
|
+
|
|
44
|
+
export default defineComponent({
|
|
45
|
+
name: "FSRangeSlider",
|
|
46
|
+
components: {
|
|
47
|
+
FSBaseField,
|
|
48
|
+
FSRow
|
|
49
|
+
},
|
|
50
|
+
props: {
|
|
51
|
+
label: {
|
|
52
|
+
type: String as PropType<string | null>,
|
|
53
|
+
required: false,
|
|
54
|
+
default: null
|
|
55
|
+
},
|
|
56
|
+
description: {
|
|
57
|
+
type: String as PropType<string | null>,
|
|
58
|
+
required: false,
|
|
59
|
+
default: null
|
|
60
|
+
},
|
|
61
|
+
modelValue: {
|
|
62
|
+
type: Object as PropType<[number, number] | null>,
|
|
63
|
+
required: false,
|
|
64
|
+
default: null
|
|
65
|
+
},
|
|
66
|
+
color: {
|
|
67
|
+
type: String as PropType<ColorBase>,
|
|
68
|
+
required: false,
|
|
69
|
+
default: ColorEnum.Dark
|
|
70
|
+
},
|
|
71
|
+
required: {
|
|
72
|
+
type: Boolean,
|
|
73
|
+
required: false,
|
|
74
|
+
default: false
|
|
75
|
+
},
|
|
76
|
+
disabled: {
|
|
77
|
+
type: Boolean,
|
|
78
|
+
required: false,
|
|
79
|
+
default: false
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
emits: ["update:modelValue"]
|
|
83
|
+
});
|
|
84
|
+
</script>
|