@bagelink/vue 1.6.47 → 1.6.51
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/bin/experimentalGenTypedRoutes.ts +18 -19
- package/bin/utils.ts +4 -4
- package/dist/components/AddressSearch.vue.d.ts.map +1 -1
- package/dist/components/Alert.vue.d.ts.map +1 -1
- package/dist/components/BglVideo.vue.d.ts.map +1 -1
- package/dist/components/Card.vue.d.ts.map +1 -1
- package/dist/components/Carousel.vue.d.ts +2 -2
- package/dist/components/Carousel.vue.d.ts.map +1 -1
- package/dist/components/Dropdown.vue.d.ts.map +1 -1
- package/dist/components/Flag.vue.d.ts.map +1 -1
- package/dist/components/IframeVue.vue.d.ts.map +1 -1
- package/dist/components/ListItem.vue.d.ts.map +1 -1
- package/dist/components/Loading.vue.d.ts.map +1 -1
- package/dist/components/Modal.vue.d.ts.map +1 -1
- package/dist/components/ModalForm.vue.d.ts.map +1 -1
- package/dist/components/NavBar.vue.d.ts +1 -1
- package/dist/components/Pill.vue.d.ts.map +1 -1
- package/dist/components/Zoomer.vue.d.ts +0 -1
- package/dist/components/Zoomer.vue.d.ts.map +1 -1
- package/dist/components/analytics/LineChart.vue.d.ts.map +1 -1
- package/dist/components/analytics/PieChart.vue.d.ts +2 -1
- package/dist/components/analytics/PieChart.vue.d.ts.map +1 -1
- package/dist/components/analytics/index.d.ts +1 -1
- package/dist/components/analytics/index.d.ts.map +1 -1
- package/dist/components/calendar/CalendarPopover.vue.d.ts.map +1 -1
- package/dist/components/form/BglMultiStepForm.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/ColorInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/DateInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/PasswordInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RadioGroup.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RangeInput.vue.d.ts +11 -11
- package/dist/components/form/inputs/RichText/components/EditorToolbar.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/components/TableGridSelector.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/utils/commands.d.ts.map +1 -1
- package/dist/components/form/inputs/SelectInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/TelInput.vue.d.ts.map +1 -1
- package/dist/components/layout/AppSidebar.vue.d.ts +1 -0
- package/dist/components/layout/AppSidebar.vue.d.ts.map +1 -1
- package/dist/components/layout/Layout.vue.d.ts.map +1 -1
- package/dist/components/layout/Tabs.vue.d.ts.map +1 -1
- package/dist/components/layout/index.d.ts +3 -3
- package/dist/components/layout/index.d.ts.map +1 -1
- package/dist/index.cjs +34 -25
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +6668 -5883
- package/dist/plugins/useToast.d.ts.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +5 -10
- package/src/components/AccordionItem.vue +11 -11
- package/src/components/AddToCalendar.vue +1 -1
- package/src/components/AddressSearch.vue +9 -8
- package/src/components/Alert.vue +2 -1
- package/src/components/Badge.vue +5 -5
- package/src/components/BglVideo.vue +44 -45
- package/src/components/Btn.vue +15 -15
- package/src/components/Card.vue +10 -8
- package/src/components/Carousel.vue +159 -162
- package/src/components/DataPreview.vue +1 -1
- package/src/components/DragOver.vue +6 -6
- package/src/components/Dropdown.vue +39 -38
- package/src/components/Flag.vue +7 -6
- package/src/components/Icon/Icon.vue +22 -22
- package/src/components/IframeVue.vue +5 -5
- package/src/components/Image.vue +17 -17
- package/src/components/ImportData.vue +79 -79
- package/src/components/ListItem.vue +20 -13
- package/src/components/Loading.vue +10 -9
- package/src/components/MapEmbed/Index.vue +24 -24
- package/src/components/Modal.vue +11 -9
- package/src/components/ModalForm.vue +9 -8
- package/src/components/NavBar.vue +6 -6
- package/src/components/Pagination.vue +27 -27
- package/src/components/Pill.vue +11 -12
- package/src/components/Rating.vue +2 -2
- package/src/components/Slider.vue +75 -75
- package/src/components/Spreadsheet/Index.vue +34 -34
- package/src/components/Spreadsheet/SpreadsheetTable.vue +3 -3
- package/src/components/Zoomer.vue +165 -170
- package/src/components/analytics/BarChart.vue +6 -6
- package/src/components/analytics/KpiCard.vue +2 -2
- package/src/components/analytics/LineChart.vue +63 -61
- package/src/components/analytics/PieChart.vue +104 -90
- package/src/components/analytics/index.ts +2 -2
- package/src/components/calendar/CalendarPopover.vue +1 -1
- package/src/components/calendar/Index.vue +1 -1
- package/src/components/calendar/views/AgendaView.vue +3 -3
- package/src/components/calendar/views/DayView.vue +6 -6
- package/src/components/calendar/views/MonthView.vue +2 -2
- package/src/components/calendar/views/WeekView.vue +18 -18
- package/src/components/dataTable/DataTable.vue +4 -4
- package/src/components/dataTable/useSorting.ts +1 -1
- package/src/components/dataTable/useTableData.ts +15 -15
- package/src/components/dataTable/useTableSelection.ts +15 -15
- package/src/components/dataTable/useTableVirtualization.ts +1 -1
- package/src/components/draggable/useDraggable.ts +42 -42
- package/src/components/form/BagelForm.vue +15 -15
- package/src/components/form/BglFieldSet.vue +5 -3
- package/src/components/form/BglMultiStepForm.vue +20 -21
- package/src/components/form/inputs/CheckInput.vue +2 -2
- package/src/components/form/inputs/CodeEditor/format.ts +7 -7
- package/src/components/form/inputs/CodeEditor/useHighlight.ts +6 -6
- package/src/components/form/inputs/ColorInput.vue +5 -4
- package/src/components/form/inputs/DateInput.vue +8 -9
- package/src/components/form/inputs/DatePicker.vue +24 -24
- package/src/components/form/inputs/EmailInput.vue +24 -24
- package/src/components/form/inputs/NumberInput.vue +26 -26
- package/src/components/form/inputs/OTP.vue +7 -7
- package/src/components/form/inputs/PasswordInput.vue +3 -2
- package/src/components/form/inputs/RadioGroup.vue +28 -25
- package/src/components/form/inputs/RadioPillsInput.vue +12 -12
- package/src/components/form/inputs/RangeInput.vue +21 -21
- package/src/components/form/inputs/RichText/components/EditorToolbar.vue +107 -92
- package/src/components/form/inputs/RichText/components/TableGridSelector.vue +64 -64
- package/src/components/form/inputs/RichText/components/gridBox.vue +10 -8
- package/src/components/form/inputs/RichText/composables/useCommands.ts +1 -1
- package/src/components/form/inputs/RichText/composables/useEditor.ts +12 -12
- package/src/components/form/inputs/RichText/composables/useEditorKeyboard.ts +1 -1
- package/src/components/form/inputs/RichText/index.vue +138 -138
- package/src/components/form/inputs/RichText/utils/commands.ts +84 -85
- package/src/components/form/inputs/RichText/utils/debug.ts +1 -1
- package/src/components/form/inputs/RichText/utils/formatting.ts +39 -39
- package/src/components/form/inputs/RichText/utils/selection.ts +28 -28
- package/src/components/form/inputs/RichText/utils/table.ts +19 -19
- package/src/components/form/inputs/SelectBtn.vue +1 -1
- package/src/components/form/inputs/SelectInput.vue +54 -54
- package/src/components/form/inputs/SignaturePad.vue +40 -40
- package/src/components/form/inputs/TableField.vue +1 -1
- package/src/components/form/inputs/TelInput.vue +54 -53
- package/src/components/form/inputs/TextInput.vue +19 -19
- package/src/components/form/inputs/ToggleInput.vue +2 -2
- package/src/components/form/inputs/Upload/useFileUpload.ts +6 -6
- package/src/components/form/useBagelFormState.ts +5 -5
- package/src/components/layout/AppLayout.vue +2 -2
- package/src/components/layout/AppSidebar.vue +77 -16
- package/src/components/layout/Layout.vue +12 -10
- package/src/components/layout/SidebarMenu.vue +4 -4
- package/src/components/layout/TabbedLayout.vue +17 -17
- package/src/components/layout/Tabs.vue +4 -5
- package/src/components/layout/TabsNav.vue +14 -14
- package/src/components/layout/index.ts +3 -5
- package/src/components/lightbox/Lightbox.vue +22 -22
- package/src/components/lightbox/index.ts +8 -8
- package/src/composables/index.ts +8 -8
- package/src/composables/useAddToCalendar.ts +13 -13
- package/src/composables/useDevice.ts +2 -2
- package/src/composables/useFormField.ts +4 -4
- package/src/composables/usePolling.ts +8 -8
- package/src/composables/useSchemaField.ts +38 -38
- package/src/composables/useTheme.ts +9 -9
- package/src/composables/useValidateFieldValue.ts +2 -2
- package/src/directives/pattern.ts +25 -25
- package/src/directives/ripple.ts +4 -4
- package/src/directives/vResize.ts +6 -6
- package/src/index.ts +1 -0
- package/src/plugins/bagel.ts +4 -4
- package/src/plugins/useToast.ts +56 -51
- package/src/styles/layout.css +1 -1
- package/src/types/index.ts +1 -1
- package/src/utils/BagelFormUtils.ts +7 -7
- package/src/utils/calendar/Helpers.ts +8 -8
- package/src/utils/calendar/dateUtils.ts +22 -22
- package/src/utils/calendar/time.ts +25 -25
- package/src/utils/calendar/week.ts +25 -25
- package/src/utils/elementUtils.ts +27 -27
- package/src/utils/sizeParsing.ts +2 -2
- package/src/utils/strings.ts +5 -5
- package/src/utils/tapDetector.ts +11 -11
- package/src/utils/useSearch.ts +29 -29
- package/vite.config.ts +0 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import { useDebounceFn } from '@bagelink/vue'
|
|
3
|
-
import { onMounted
|
|
3
|
+
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
|
4
4
|
import TapDetector from '../utils/tapDetector'
|
|
5
5
|
|
|
6
6
|
// Props interface
|
|
@@ -9,7 +9,6 @@ interface Props {
|
|
|
9
9
|
maxScale?: number
|
|
10
10
|
zoom?: number
|
|
11
11
|
resetTrigger?: number
|
|
12
|
-
aspectRatio?: number
|
|
13
12
|
backgroundColor?: string
|
|
14
13
|
pivot?: string // 'cursor' | 'image-center'
|
|
15
14
|
zoomingElastic?: boolean
|
|
@@ -24,7 +23,6 @@ const {
|
|
|
24
23
|
maxScale = 5,
|
|
25
24
|
zoom,
|
|
26
25
|
disabled = false,
|
|
27
|
-
aspectRatio = 1,
|
|
28
26
|
backgroundColor = 'transparent',
|
|
29
27
|
pivot = 'cursor',
|
|
30
28
|
zoomingElastic = true,
|
|
@@ -34,87 +32,84 @@ const {
|
|
|
34
32
|
} = defineProps<Props>()
|
|
35
33
|
|
|
36
34
|
const emit = defineEmits(['update:zoom'])
|
|
37
|
-
// Reactive state using
|
|
38
|
-
const zoomElement =
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
get: () => zoom ?? _zoom,
|
|
35
|
+
// Reactive state using standard Vue composition API
|
|
36
|
+
const zoomElement = ref<HTMLElement | undefined>()
|
|
37
|
+
const containerWidth = ref(1)
|
|
38
|
+
const containerHeight = ref(1)
|
|
39
|
+
const containerLeft = ref(0)
|
|
40
|
+
const containerTop = ref(0)
|
|
41
|
+
const translateX = ref(0)
|
|
42
|
+
const animTranslateX = ref(0)
|
|
43
|
+
const translateY = ref(0)
|
|
44
|
+
const animTranslateY = ref(0)
|
|
45
|
+
const _zoom = ref(zoom ?? 1)
|
|
46
|
+
const scale = computed({
|
|
47
|
+
get: () => zoom ?? _zoom.value,
|
|
50
48
|
set: (val) => {
|
|
51
|
-
_zoom = val
|
|
52
|
-
emit('update:zoom', _zoom)
|
|
49
|
+
_zoom.value = val
|
|
50
|
+
emit('update:zoom', _zoom.value)
|
|
53
51
|
},
|
|
54
52
|
})
|
|
55
53
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
let translateXValue = $ref(0)
|
|
69
|
-
let translateYValue = $ref(0)
|
|
54
|
+
const animScale = ref(1)
|
|
55
|
+
const lastFullWheelTime = ref(0)
|
|
56
|
+
const lastWheelTime = ref(0)
|
|
57
|
+
const lastWheelDirection = ref<'x' | 'y'>('y')
|
|
58
|
+
const isPointerDown = ref(false)
|
|
59
|
+
const pointerPosX = ref(-1)
|
|
60
|
+
const pointerPosY = ref(-1)
|
|
61
|
+
const twoFingerInitDist = ref(0)
|
|
62
|
+
const panLocked = ref(true)
|
|
63
|
+
const raf = ref<number | undefined>()
|
|
64
|
+
const tapDetector = ref<TapDetector | undefined>()
|
|
70
65
|
|
|
71
66
|
// Momentum/inertia tracking
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
67
|
+
const velocityX = ref(0)
|
|
68
|
+
const velocityY = ref(0)
|
|
69
|
+
const lastMoveTime = ref(0)
|
|
70
|
+
const momentumRaf = ref<number | undefined>()
|
|
76
71
|
|
|
77
|
-
const wrapperStyle =
|
|
72
|
+
const wrapperStyle = computed(() => {
|
|
78
73
|
// Translation is in normalized coordinates (0.5 = half container)
|
|
79
74
|
// Convert to pixels
|
|
80
|
-
translateXValue = containerWidth * animTranslateX
|
|
81
|
-
translateYValue = containerHeight * animTranslateY
|
|
75
|
+
const translateXValue = containerWidth.value * animTranslateX.value
|
|
76
|
+
const translateYValue = containerHeight.value * animTranslateY.value
|
|
82
77
|
return {
|
|
83
78
|
transform: [
|
|
84
79
|
`translate(${translateXValue}px, ${translateYValue}px)`,
|
|
85
|
-
`scale(${animScale})`,
|
|
80
|
+
`scale(${animScale.value})`,
|
|
86
81
|
].join(' '),
|
|
87
82
|
transformOrigin: '50% 50%',
|
|
88
83
|
}
|
|
89
84
|
})
|
|
90
85
|
|
|
91
|
-
|
|
86
|
+
watch(() => scale.value, (newScale) => {
|
|
92
87
|
const { x, y } = calcTranslateLimit()
|
|
93
|
-
translateX = Math.max(-x, Math.min(x, translateX))
|
|
94
|
-
translateY = Math.max(-y, Math.min(y, translateY))
|
|
88
|
+
translateX.value = Math.max(-x, Math.min(x, translateX.value))
|
|
89
|
+
translateY.value = Math.max(-y, Math.min(y, translateY.value))
|
|
95
90
|
if (newScale !== 1) {
|
|
96
|
-
panLocked = false
|
|
91
|
+
panLocked.value = false
|
|
97
92
|
}
|
|
98
93
|
})
|
|
99
94
|
|
|
100
95
|
function reset() {
|
|
101
|
-
scale = 1
|
|
102
|
-
panLocked = true
|
|
103
|
-
translateX = 0
|
|
104
|
-
translateY = 0
|
|
96
|
+
scale.value = 1
|
|
97
|
+
panLocked.value = true
|
|
98
|
+
translateX.value = 0
|
|
99
|
+
translateY.value = 0
|
|
105
100
|
}
|
|
106
101
|
|
|
107
102
|
defineExpose({ reset })
|
|
108
103
|
|
|
109
104
|
function tryToScale(scaleDelta: number) {
|
|
110
105
|
if (disabled) { return }
|
|
111
|
-
let newScale = scale * scaleDelta
|
|
106
|
+
let newScale = scale.value * scaleDelta
|
|
112
107
|
if (zoomingElastic) {
|
|
113
108
|
if (newScale < minScale || newScale > maxScale) {
|
|
114
109
|
let log = Math.log2(scaleDelta)
|
|
115
110
|
log *= 0.2
|
|
116
111
|
scaleDelta = 2 ** log
|
|
117
|
-
newScale = scale * scaleDelta
|
|
112
|
+
newScale = scale.value * scaleDelta
|
|
118
113
|
}
|
|
119
114
|
} else {
|
|
120
115
|
if (newScale < minScale) {
|
|
@@ -123,104 +118,104 @@ function tryToScale(scaleDelta: number) {
|
|
|
123
118
|
newScale = maxScale
|
|
124
119
|
}
|
|
125
120
|
}
|
|
126
|
-
scaleDelta = newScale / scale
|
|
127
|
-
scale = newScale
|
|
121
|
+
scaleDelta = newScale / scale.value
|
|
122
|
+
scale.value = newScale
|
|
128
123
|
if (pivot !== 'image-center') {
|
|
129
|
-
const normMousePosX = (pointerPosX - containerLeft) / containerWidth
|
|
130
|
-
const normMousePosY = (pointerPosY - containerTop) / containerHeight
|
|
131
|
-
translateX = (0.5 + translateX - normMousePosX) * scaleDelta + normMousePosX - 0.5
|
|
132
|
-
translateY = (0.5 + translateY - normMousePosY) * scaleDelta + normMousePosY - 0.5
|
|
124
|
+
const normMousePosX = (pointerPosX.value - containerLeft.value) / containerWidth.value
|
|
125
|
+
const normMousePosY = (pointerPosY.value - containerTop.value) / containerHeight.value
|
|
126
|
+
translateX.value = (0.5 + translateX.value - normMousePosX) * scaleDelta + normMousePosX - 0.5
|
|
127
|
+
translateY.value = (0.5 + translateY.value - normMousePosY) * scaleDelta + normMousePosY - 0.5
|
|
133
128
|
}
|
|
134
129
|
}
|
|
135
130
|
|
|
136
131
|
function setPointerPosCenter() {
|
|
137
|
-
pointerPosX = containerLeft + containerWidth / 2
|
|
138
|
-
pointerPosY = containerTop + containerHeight / 2
|
|
132
|
+
pointerPosX.value = containerLeft.value + containerWidth.value / 2
|
|
133
|
+
pointerPosY.value = containerTop.value + containerHeight.value / 2
|
|
139
134
|
}
|
|
140
135
|
|
|
141
136
|
function onPointerMove(newMousePosX: number, newMousePosY: number) {
|
|
142
|
-
if (isPointerDown) {
|
|
137
|
+
if (isPointerDown.value) {
|
|
143
138
|
const currentTime = Date.now()
|
|
144
|
-
const pixelDeltaX = newMousePosX - pointerPosX
|
|
145
|
-
const pixelDeltaY = newMousePosY - pointerPosY
|
|
139
|
+
const pixelDeltaX = newMousePosX - pointerPosX.value
|
|
140
|
+
const pixelDeltaY = newMousePosY - pointerPosY.value
|
|
146
141
|
|
|
147
|
-
if (!panLocked) {
|
|
142
|
+
if (!panLocked.value) {
|
|
148
143
|
// Calculate velocity for momentum
|
|
149
|
-
const timeDelta = currentTime - lastMoveTime
|
|
144
|
+
const timeDelta = currentTime - lastMoveTime.value
|
|
150
145
|
if (timeDelta > 0) {
|
|
151
|
-
velocityX = pixelDeltaX / timeDelta
|
|
152
|
-
velocityY = pixelDeltaY / timeDelta
|
|
146
|
+
velocityX.value = pixelDeltaX / timeDelta
|
|
147
|
+
velocityY.value = pixelDeltaY / timeDelta
|
|
153
148
|
}
|
|
154
149
|
|
|
155
150
|
const translateLimit = calcTranslateLimit()
|
|
156
151
|
const maxTranslateX = translateLimit.x
|
|
157
152
|
const maxTranslateY = translateLimit.y
|
|
158
|
-
const newTranslateX = translateX + pixelDeltaX / containerWidth
|
|
159
|
-
const newTranslateY = translateY + pixelDeltaY / containerHeight
|
|
153
|
+
const newTranslateX = translateX.value + pixelDeltaX / containerWidth.value
|
|
154
|
+
const newTranslateY = translateY.value + pixelDeltaY / containerHeight.value
|
|
160
155
|
|
|
161
|
-
translateX = Math.max(-maxTranslateX, Math.min(maxTranslateX, newTranslateX))
|
|
162
|
-
translateY = Math.max(-maxTranslateY, Math.min(maxTranslateY, newTranslateY))
|
|
156
|
+
translateX.value = Math.max(-maxTranslateX, Math.min(maxTranslateX, newTranslateX))
|
|
157
|
+
translateY.value = Math.max(-maxTranslateY, Math.min(maxTranslateY, newTranslateY))
|
|
163
158
|
|
|
164
|
-
lastMoveTime = currentTime
|
|
159
|
+
lastMoveTime.value = currentTime
|
|
165
160
|
}
|
|
166
161
|
}
|
|
167
|
-
pointerPosX = newMousePosX
|
|
168
|
-
pointerPosY = newMousePosY
|
|
162
|
+
pointerPosX.value = newMousePosX
|
|
163
|
+
pointerPosY.value = newMousePosY
|
|
169
164
|
}
|
|
170
165
|
|
|
171
166
|
function applyMomentum() {
|
|
172
|
-
if (Math.abs(velocityX) < 0.01 && Math.abs(velocityY) < 0.01) {
|
|
173
|
-
velocityX = 0
|
|
174
|
-
velocityY = 0
|
|
175
|
-
if (momentumRaf) {
|
|
176
|
-
cancelAnimationFrame(momentumRaf)
|
|
177
|
-
momentumRaf = undefined
|
|
167
|
+
if (Math.abs(velocityX.value) < 0.01 && Math.abs(velocityY.value) < 0.01) {
|
|
168
|
+
velocityX.value = 0
|
|
169
|
+
velocityY.value = 0
|
|
170
|
+
if (momentumRaf.value) {
|
|
171
|
+
cancelAnimationFrame(momentumRaf.value)
|
|
172
|
+
momentumRaf.value = undefined
|
|
178
173
|
}
|
|
179
174
|
return
|
|
180
175
|
}
|
|
181
176
|
|
|
182
177
|
const translateLimit = calcTranslateLimit()
|
|
183
|
-
const newTranslateX = translateX + velocityX * 16 / containerWidth
|
|
184
|
-
const newTranslateY = translateY + velocityY * 16 / containerHeight
|
|
178
|
+
const newTranslateX = translateX.value + velocityX.value * 16 / containerWidth.value
|
|
179
|
+
const newTranslateY = translateY.value + velocityY.value * 16 / containerHeight.value
|
|
185
180
|
|
|
186
|
-
translateX = Math.max(-translateLimit.x, Math.min(translateLimit.x, newTranslateX))
|
|
187
|
-
translateY = Math.max(-translateLimit.y, Math.min(translateLimit.y, newTranslateY))
|
|
181
|
+
translateX.value = Math.max(-translateLimit.x, Math.min(translateLimit.x, newTranslateX))
|
|
182
|
+
translateY.value = Math.max(-translateLimit.y, Math.min(translateLimit.y, newTranslateY))
|
|
188
183
|
|
|
189
184
|
// Apply friction
|
|
190
|
-
velocityX *= 0.95
|
|
191
|
-
velocityY *= 0.95
|
|
185
|
+
velocityX.value *= 0.95
|
|
186
|
+
velocityY.value *= 0.95
|
|
192
187
|
|
|
193
|
-
momentumRaf = requestAnimationFrame(applyMomentum)
|
|
188
|
+
momentumRaf.value = requestAnimationFrame(applyMomentum)
|
|
194
189
|
}
|
|
195
190
|
|
|
196
191
|
const onInteractionEnd = useDebounceFn(() => {
|
|
197
192
|
limit()
|
|
198
|
-
panLocked = scale === 1
|
|
193
|
+
panLocked.value = scale.value === 1
|
|
199
194
|
|
|
200
195
|
// Start momentum animation if there's significant velocity
|
|
201
|
-
if (!panLocked && (Math.abs(velocityX) > 0.1 || Math.abs(velocityY) > 0.1)) {
|
|
202
|
-
if (momentumRaf) cancelAnimationFrame(momentumRaf)
|
|
196
|
+
if (!panLocked.value && (Math.abs(velocityX.value) > 0.1 || Math.abs(velocityY.value) > 0.1)) {
|
|
197
|
+
if (momentumRaf.value) cancelAnimationFrame(momentumRaf.value)
|
|
203
198
|
applyMomentum()
|
|
204
199
|
} else {
|
|
205
|
-
velocityX = 0
|
|
206
|
-
velocityY = 0
|
|
200
|
+
velocityX.value = 0
|
|
201
|
+
velocityY.value = 0
|
|
207
202
|
}
|
|
208
203
|
}, 50)
|
|
209
204
|
|
|
210
205
|
function limit() {
|
|
211
|
-
if (scale < minScale) {
|
|
212
|
-
scale = minScale
|
|
213
|
-
} else if (scale > maxScale) {
|
|
214
|
-
tryToScale(maxScale / scale)
|
|
206
|
+
if (scale.value < minScale) {
|
|
207
|
+
scale.value = minScale
|
|
208
|
+
} else if (scale.value > maxScale) {
|
|
209
|
+
tryToScale(maxScale / scale.value)
|
|
215
210
|
}
|
|
216
211
|
|
|
217
212
|
if (limitTranslation) {
|
|
218
213
|
const translateLimit = calcTranslateLimit()
|
|
219
|
-
if (Math.abs(translateX) > translateLimit.x) {
|
|
220
|
-
translateX *= translateLimit.x / Math.abs(translateX)
|
|
214
|
+
if (Math.abs(translateX.value) > translateLimit.x) {
|
|
215
|
+
translateX.value *= translateLimit.x / Math.abs(translateX.value)
|
|
221
216
|
}
|
|
222
|
-
if (Math.abs(translateY) > translateLimit.y) {
|
|
223
|
-
translateY *= translateLimit.y / Math.abs(translateY)
|
|
217
|
+
if (Math.abs(translateY.value) > translateLimit.y) {
|
|
218
|
+
translateY.value *= translateLimit.y / Math.abs(translateY.value)
|
|
224
219
|
}
|
|
225
220
|
}
|
|
226
221
|
}
|
|
@@ -238,7 +233,7 @@ function calcTranslateLimit() {
|
|
|
238
233
|
// Max pan distance in normalized coords = (scale - 1) / 2
|
|
239
234
|
// This works for both X and Y directions regardless of aspect ratio
|
|
240
235
|
|
|
241
|
-
const basePanLimit = Math.max(0, (scale - 1) / 2)
|
|
236
|
+
const basePanLimit = Math.max(0, (scale.value - 1) / 2)
|
|
242
237
|
|
|
243
238
|
return {
|
|
244
239
|
x: basePanLimit,
|
|
@@ -251,18 +246,18 @@ function onMouseWheel(ev: WheelEvent) {
|
|
|
251
246
|
ev.preventDefault()
|
|
252
247
|
const currTime = Date.now()
|
|
253
248
|
if (Math.abs(ev.deltaY) === 120) {
|
|
254
|
-
if (currTime - lastFullWheelTime > 50) {
|
|
249
|
+
if (currTime - lastFullWheelTime.value > 50) {
|
|
255
250
|
onMouseWheelDo(ev.deltaY)
|
|
256
|
-
lastFullWheelTime = currTime
|
|
251
|
+
lastFullWheelTime.value = currTime
|
|
257
252
|
}
|
|
258
253
|
} else {
|
|
259
|
-
if (currTime - lastWheelTime > 50) {
|
|
260
|
-
lastWheelDirection = ev.deltaX > ev.deltaY ? 'x' : 'y'
|
|
261
|
-
if (lastWheelDirection === 'y') {
|
|
254
|
+
if (currTime - lastWheelTime.value > 50) {
|
|
255
|
+
lastWheelDirection.value = ev.deltaX > ev.deltaY ? 'x' : 'y'
|
|
256
|
+
if (lastWheelDirection.value === 'y') {
|
|
262
257
|
onMouseWheelDo(ev.deltaY)
|
|
263
258
|
}
|
|
264
259
|
}
|
|
265
|
-
lastWheelTime = currTime
|
|
260
|
+
lastWheelTime.value = currTime
|
|
266
261
|
}
|
|
267
262
|
}
|
|
268
263
|
|
|
@@ -275,22 +270,22 @@ function onMouseWheelDo(wheelDelta: number) {
|
|
|
275
270
|
|
|
276
271
|
function onMouseDown(ev: MouseEvent) {
|
|
277
272
|
refreshContainerPos()
|
|
278
|
-
isPointerDown = true
|
|
279
|
-
pointerPosX = ev.clientX
|
|
280
|
-
pointerPosY = ev.clientY
|
|
281
|
-
lastMoveTime = Date.now()
|
|
282
|
-
velocityX = 0
|
|
283
|
-
velocityY = 0
|
|
284
|
-
if (momentumRaf) {
|
|
285
|
-
cancelAnimationFrame(momentumRaf)
|
|
286
|
-
momentumRaf = undefined
|
|
273
|
+
isPointerDown.value = true
|
|
274
|
+
pointerPosX.value = ev.clientX
|
|
275
|
+
pointerPosY.value = ev.clientY
|
|
276
|
+
lastMoveTime.value = Date.now()
|
|
277
|
+
velocityX.value = 0
|
|
278
|
+
velocityY.value = 0
|
|
279
|
+
if (momentumRaf.value) {
|
|
280
|
+
cancelAnimationFrame(momentumRaf.value)
|
|
281
|
+
momentumRaf.value = undefined
|
|
287
282
|
}
|
|
288
283
|
document.addEventListener('mousemove', onMouseMove)
|
|
289
284
|
document.addEventListener('mouseup', onMouseUp)
|
|
290
285
|
}
|
|
291
286
|
|
|
292
287
|
function onMouseUp() {
|
|
293
|
-
isPointerDown = false
|
|
288
|
+
isPointerDown.value = false
|
|
294
289
|
onInteractionEnd()
|
|
295
290
|
document.removeEventListener('mouseup', onMouseUp)
|
|
296
291
|
document.removeEventListener('mousemove', onMouseMove)
|
|
@@ -298,7 +293,7 @@ function onMouseUp() {
|
|
|
298
293
|
|
|
299
294
|
function onMouseMove(ev: MouseEvent) {
|
|
300
295
|
// Prevent swiper from handling mouse drag when panning zoomed image
|
|
301
|
-
if (!panLocked && scale > 1) {
|
|
296
|
+
if (!panLocked.value && scale.value > 1) {
|
|
302
297
|
ev.stopPropagation()
|
|
303
298
|
}
|
|
304
299
|
onPointerMove(ev.clientX, ev.clientY)
|
|
@@ -307,41 +302,41 @@ function onMouseMove(ev: MouseEvent) {
|
|
|
307
302
|
function onTouchStart(ev: TouchEvent) {
|
|
308
303
|
if (ev.touches.length === 1) {
|
|
309
304
|
refreshContainerPos()
|
|
310
|
-
pointerPosX = ev.touches[0].clientX
|
|
311
|
-
pointerPosY = ev.touches[0].clientY
|
|
312
|
-
lastMoveTime = Date.now()
|
|
313
|
-
velocityX = 0
|
|
314
|
-
velocityY = 0
|
|
315
|
-
if (momentumRaf) {
|
|
316
|
-
cancelAnimationFrame(momentumRaf)
|
|
317
|
-
momentumRaf = undefined
|
|
305
|
+
pointerPosX.value = ev.touches[0].clientX
|
|
306
|
+
pointerPosY.value = ev.touches[0].clientY
|
|
307
|
+
lastMoveTime.value = Date.now()
|
|
308
|
+
velocityX.value = 0
|
|
309
|
+
velocityY.value = 0
|
|
310
|
+
if (momentumRaf.value) {
|
|
311
|
+
cancelAnimationFrame(momentumRaf.value)
|
|
312
|
+
momentumRaf.value = undefined
|
|
318
313
|
}
|
|
319
|
-
isPointerDown = true
|
|
314
|
+
isPointerDown.value = true
|
|
320
315
|
} else if (ev.touches.length === 2) {
|
|
321
|
-
if (momentumRaf) {
|
|
322
|
-
cancelAnimationFrame(momentumRaf)
|
|
323
|
-
momentumRaf = undefined
|
|
316
|
+
if (momentumRaf.value) {
|
|
317
|
+
cancelAnimationFrame(momentumRaf.value)
|
|
318
|
+
momentumRaf.value = undefined
|
|
324
319
|
}
|
|
325
|
-
velocityX = 0
|
|
326
|
-
velocityY = 0
|
|
327
|
-
isPointerDown = true
|
|
328
|
-
pointerPosX = (ev.touches[0].clientX + ev.touches[1].clientX) / 2
|
|
329
|
-
pointerPosY = (ev.touches[0].clientY + ev.touches[1].clientY) / 2
|
|
320
|
+
velocityX.value = 0
|
|
321
|
+
velocityY.value = 0
|
|
322
|
+
isPointerDown.value = true
|
|
323
|
+
pointerPosX.value = (ev.touches[0].clientX + ev.touches[1].clientX) / 2
|
|
324
|
+
pointerPosY.value = (ev.touches[0].clientY + ev.touches[1].clientY) / 2
|
|
330
325
|
const distX = ev.touches[0].clientX - ev.touches[1].clientX
|
|
331
326
|
const distY = ev.touches[0].clientY - ev.touches[1].clientY
|
|
332
|
-
twoFingerInitDist = Math.sqrt(distX * distX + distY * distY)
|
|
327
|
+
twoFingerInitDist.value = Math.sqrt(distX * distX + distY * distY)
|
|
333
328
|
}
|
|
334
329
|
document.addEventListener('touchend', onTouchEnd)
|
|
335
330
|
}
|
|
336
331
|
|
|
337
332
|
function onTouchEnd(ev: TouchEvent) {
|
|
338
333
|
if (ev.touches.length === 0) {
|
|
339
|
-
isPointerDown = false
|
|
340
|
-
if (Math.abs(scale - 1) < 0.1) { scale = 1 }
|
|
334
|
+
isPointerDown.value = false
|
|
335
|
+
if (Math.abs(scale.value - 1) < 0.1) { scale.value = 1 }
|
|
341
336
|
onInteractionEnd()
|
|
342
337
|
} else if (ev.touches.length === 1) {
|
|
343
|
-
pointerPosX = ev.touches[0].clientX
|
|
344
|
-
pointerPosY = ev.touches[0].clientY
|
|
338
|
+
pointerPosX.value = ev.touches[0].clientX
|
|
339
|
+
pointerPosY.value = ev.touches[0].clientY
|
|
345
340
|
}
|
|
346
341
|
document.removeEventListener('touchend', onTouchEnd)
|
|
347
342
|
}
|
|
@@ -349,7 +344,7 @@ function onTouchEnd(ev: TouchEvent) {
|
|
|
349
344
|
function onTouchMove(ev: TouchEvent) {
|
|
350
345
|
if (ev.touches.length === 1) {
|
|
351
346
|
// Prevent swiper from handling touch when panning zoomed image
|
|
352
|
-
if (!panLocked && scale > 1) {
|
|
347
|
+
if (!panLocked.value && scale.value > 1) {
|
|
353
348
|
ev.stopPropagation()
|
|
354
349
|
}
|
|
355
350
|
onPointerMove(ev.touches[0].clientX, ev.touches[0].clientY)
|
|
@@ -359,24 +354,24 @@ function onTouchMove(ev: TouchEvent) {
|
|
|
359
354
|
const distX = ev.touches[0].clientX - ev.touches[1].clientX
|
|
360
355
|
const distY = ev.touches[0].clientY - ev.touches[1].clientY
|
|
361
356
|
const newTwoFingerDist = Math.sqrt(distX * distX + distY * distY)
|
|
362
|
-
tryToScale(newTwoFingerDist / twoFingerInitDist)
|
|
363
|
-
twoFingerInitDist = newTwoFingerDist
|
|
357
|
+
tryToScale(newTwoFingerDist / twoFingerInitDist.value)
|
|
358
|
+
twoFingerInitDist.value = newTwoFingerDist
|
|
364
359
|
}
|
|
365
360
|
}
|
|
366
361
|
|
|
367
362
|
function refreshContainerPos() {
|
|
368
|
-
if (zoomElement) {
|
|
369
|
-
const rect = zoomElement.getBoundingClientRect()
|
|
370
|
-
containerLeft = rect.left
|
|
371
|
-
containerTop = rect.top
|
|
363
|
+
if (zoomElement.value) {
|
|
364
|
+
const rect = zoomElement.value.getBoundingClientRect()
|
|
365
|
+
containerLeft.value = rect.left
|
|
366
|
+
containerTop.value = rect.top
|
|
372
367
|
}
|
|
373
368
|
}
|
|
374
369
|
|
|
375
370
|
function loop() {
|
|
376
|
-
animScale = gainOn(animScale, scale)
|
|
377
|
-
animTranslateX = gainOn(animTranslateX, translateX)
|
|
378
|
-
animTranslateY = gainOn(animTranslateY, translateY)
|
|
379
|
-
raf = window.requestAnimationFrame(loop)
|
|
371
|
+
animScale.value = gainOn(animScale.value, scale.value)
|
|
372
|
+
animTranslateX.value = gainOn(animTranslateX.value, translateX.value)
|
|
373
|
+
animTranslateY.value = gainOn(animTranslateY.value, translateY.value)
|
|
374
|
+
raf.value = window.requestAnimationFrame(loop)
|
|
380
375
|
}
|
|
381
376
|
|
|
382
377
|
function gainOn(from: number, to: number) {
|
|
@@ -386,14 +381,14 @@ function gainOn(from: number, to: number) {
|
|
|
386
381
|
}
|
|
387
382
|
|
|
388
383
|
// Lifecycle hooks
|
|
389
|
-
|
|
390
|
-
tapDetector = new TapDetector()
|
|
391
|
-
if (zoomElement) { tapDetector.attach(zoomElement) }
|
|
384
|
+
onMounted(() => {
|
|
385
|
+
tapDetector.value = new TapDetector()
|
|
386
|
+
if (zoomElement.value) { tapDetector.value.attach(zoomElement.value) }
|
|
392
387
|
if (doubleClickToZoom) {
|
|
393
|
-
tapDetector.onDoubleTap(onDoubleTap as any)
|
|
388
|
+
tapDetector.value.onDoubleTap(onDoubleTap as any)
|
|
394
389
|
// Also add native dblclick event for mouse
|
|
395
|
-
if (zoomElement) {
|
|
396
|
-
zoomElement.addEventListener('dblclick', onDoubleTap as any)
|
|
390
|
+
if (zoomElement.value) {
|
|
391
|
+
zoomElement.value.addEventListener('dblclick', onDoubleTap as any)
|
|
397
392
|
}
|
|
398
393
|
}
|
|
399
394
|
window.addEventListener('resize', onWindowResize)
|
|
@@ -402,23 +397,23 @@ vueOnMounted(() => {
|
|
|
402
397
|
loop()
|
|
403
398
|
})
|
|
404
399
|
|
|
405
|
-
|
|
406
|
-
if (zoomElement) {
|
|
407
|
-
tapDetector?.detach(zoomElement)
|
|
400
|
+
onUnmounted(() => {
|
|
401
|
+
if (zoomElement.value) {
|
|
402
|
+
tapDetector.value?.detach(zoomElement.value)
|
|
408
403
|
if (doubleClickToZoom) {
|
|
409
|
-
zoomElement.removeEventListener('dblclick', onDoubleTap as any)
|
|
404
|
+
zoomElement.value.removeEventListener('dblclick', onDoubleTap as any)
|
|
410
405
|
}
|
|
411
406
|
}
|
|
412
407
|
window.removeEventListener('resize', onWindowResize)
|
|
413
|
-
if (raf) { window.cancelAnimationFrame(raf) }
|
|
414
|
-
if (momentumRaf) { window.cancelAnimationFrame(momentumRaf) }
|
|
408
|
+
if (raf.value) { window.cancelAnimationFrame(raf.value) }
|
|
409
|
+
if (momentumRaf.value) { window.cancelAnimationFrame(momentumRaf.value) }
|
|
415
410
|
})
|
|
416
411
|
|
|
417
412
|
function onDoubleTap(ev: MouseEvent) {
|
|
418
413
|
// Update pointer position if available
|
|
419
414
|
if (ev.clientX > 0) {
|
|
420
|
-
pointerPosX = ev.clientX
|
|
421
|
-
pointerPosY = ev.clientY
|
|
415
|
+
pointerPosX.value = ev.clientX
|
|
416
|
+
pointerPosY.value = ev.clientY
|
|
422
417
|
}
|
|
423
418
|
|
|
424
419
|
// Calculate zoom levels
|
|
@@ -426,12 +421,12 @@ function onDoubleTap(ev: MouseEvent) {
|
|
|
426
421
|
const highZoom = maxScale
|
|
427
422
|
|
|
428
423
|
// Cycle through three states: 1x -> medium -> max -> 1x
|
|
429
|
-
if (scale === 1) {
|
|
424
|
+
if (scale.value === 1) {
|
|
430
425
|
// From no zoom -> medium zoom
|
|
431
426
|
tryToScale(mediumZoom)
|
|
432
|
-
} else if (scale < highZoom - 0.1) {
|
|
427
|
+
} else if (scale.value < highZoom - 0.1) {
|
|
433
428
|
// From medium zoom -> max zoom
|
|
434
|
-
tryToScale(highZoom / scale)
|
|
429
|
+
tryToScale(highZoom / scale.value)
|
|
435
430
|
} else {
|
|
436
431
|
// From max zoom -> no zoom (reset)
|
|
437
432
|
reset()
|
|
@@ -439,10 +434,10 @@ function onDoubleTap(ev: MouseEvent) {
|
|
|
439
434
|
}
|
|
440
435
|
|
|
441
436
|
function onWindowResize() {
|
|
442
|
-
if (zoomElement) {
|
|
443
|
-
const styles = window.getComputedStyle(zoomElement)
|
|
444
|
-
containerWidth = Number.parseFloat(styles.width)
|
|
445
|
-
containerHeight = Number.parseFloat(styles.height)
|
|
437
|
+
if (zoomElement.value) {
|
|
438
|
+
const styles = window.getComputedStyle(zoomElement.value)
|
|
439
|
+
containerWidth.value = Number.parseFloat(styles.width)
|
|
440
|
+
containerHeight.value = Number.parseFloat(styles.height)
|
|
446
441
|
setPointerPosCenter()
|
|
447
442
|
limit()
|
|
448
443
|
}
|
|
@@ -57,7 +57,7 @@ const observer = ref<IntersectionObserver | null>(null)
|
|
|
57
57
|
const chartRef = ref<HTMLElement | null>(null)
|
|
58
58
|
|
|
59
59
|
const chartData = computed(() => {
|
|
60
|
-
if (!props.data ||
|
|
60
|
+
if (!props.data || props.data.length === 0) { return [] }
|
|
61
61
|
|
|
62
62
|
// Use all data without limiting to maxBars
|
|
63
63
|
const maxValue = Math.max(...props.data.map(d => d.value), 1)
|
|
@@ -71,8 +71,8 @@ const chartData = computed(() => {
|
|
|
71
71
|
// Animation computed properties
|
|
72
72
|
const getBarOpacity = computed(() => {
|
|
73
73
|
return (index: number) => {
|
|
74
|
-
if (!props.animated) {return 1}
|
|
75
|
-
if (!isInView.value) {return 0}
|
|
74
|
+
if (!props.animated) { return 1 }
|
|
75
|
+
if (!isInView.value) { return 0 }
|
|
76
76
|
|
|
77
77
|
const totalBars = chartData.value.length
|
|
78
78
|
|
|
@@ -90,7 +90,7 @@ function easeOutCubic(t: number): number {
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
function startAnimation() {
|
|
93
|
-
if (isAnimating.value || !props.animated) {return}
|
|
93
|
+
if (isAnimating.value || !props.animated) { return }
|
|
94
94
|
|
|
95
95
|
console.log(`🎯 TrendChart: Starting animation with ${props.animationDuration}ms duration`)
|
|
96
96
|
isAnimating.value = true
|
|
@@ -105,7 +105,7 @@ function startAnimation() {
|
|
|
105
105
|
|
|
106
106
|
animatedProgress.value = easedProgress
|
|
107
107
|
|
|
108
|
-
if (
|
|
108
|
+
if (progress < 1) {
|
|
109
109
|
requestAnimationFrame(animate)
|
|
110
110
|
} else {
|
|
111
111
|
isAnimating.value = false
|
|
@@ -117,7 +117,7 @@ function startAnimation() {
|
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
function setupIntersectionObserver() {
|
|
120
|
-
if (!chartRef.value || observer.value) {return}
|
|
120
|
+
if (!chartRef.value || observer.value) { return }
|
|
121
121
|
|
|
122
122
|
observer.value = new IntersectionObserver(
|
|
123
123
|
(entries) => {
|
|
@@ -27,10 +27,10 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
27
27
|
subtitle: ''
|
|
28
28
|
})
|
|
29
29
|
|
|
30
|
-
const isIncreasing = computed(() =>
|
|
30
|
+
const isIncreasing = computed(() => props.percentageChange >= 0)
|
|
31
31
|
|
|
32
32
|
const formattedValue = computed(() => {
|
|
33
|
-
if (
|
|
33
|
+
if (typeof props.value === 'string') { return props.value }
|
|
34
34
|
|
|
35
35
|
if (props.currency) {
|
|
36
36
|
return new Intl.NumberFormat('he-IL', {
|