Skip to content

Commit e2bc4c2

Browse files
committed
update fmv functionality
1 parent 523884a commit e2bc4c2

File tree

4 files changed

+87
-2
lines changed

4 files changed

+87
-2
lines changed

client/src/components/FMVLayerConfig.vue

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,26 @@ export default defineComponent({
3535
},
3636
});
3737
38+
const playingWhileDraggin = ref(false);
39+
40+
const startDraggingFrameSlider = () => {
41+
if (fmvStore.value) {
42+
playingWhileDraggin.value = fmvStore.value.videoState === 'playing';
43+
if (playingWhileDraggin.value) {
44+
fmvStore.value.setVideoState('pause');
45+
}
46+
}
47+
};
48+
49+
const stopDraggingFrameSlider = () => {
50+
if (playingWhileDraggin.value) {
51+
playingWhileDraggin.value = false;
52+
if (fmvStore.value) {
53+
fmvStore.value.setVideoState('playing');
54+
}
55+
}
56+
};
57+
3858
const lockZoom = computed({
3959
get: () => fmvStore.value?.lockZoom ?? false,
4060
set: (val) => {
@@ -162,13 +182,17 @@ export default defineComponent({
162182
togglePlayback();
163183
break;
164184
case 'ArrowLeft':
185+
event.stopPropagation();
186+
event.preventDefault();
165187
if (!keyHoldInterval) {
166188
// Do one frame step immediately
167189
jumpFrame('left', 1);
168190
startFrameJump('left');
169191
}
170192
break;
171193
case 'ArrowRight':
194+
event.stopPropagation();
195+
event.preventDefault();
172196
if (!keyHoldInterval) {
173197
// Do one frame step immediately
174198
jumpFrame('right', 1);
@@ -196,7 +220,15 @@ export default defineComponent({
196220
window.removeEventListener('keyup', handleKeyup);
197221
stopFrameJump();
198222
});
223+
const speedTicks = ref([0.25, 0.5, 0.75, 1.0, 2.0, 4.0, 8.0]);
224+
const speed = ref(1);
199225
226+
const setSpeed = (newSpeed: number) => {
227+
if (fmvStore.value) {
228+
speed.value = newSpeed;
229+
fmvStore.value.setPlaybackSpeed(newSpeed);
230+
}
231+
};
200232
return {
201233
frameId,
202234
visibleProperties,
@@ -210,6 +242,11 @@ export default defineComponent({
210242
opacity,
211243
lockZoom,
212244
zoomBounds,
245+
speedTicks,
246+
speed,
247+
setSpeed,
248+
startDraggingFrameSlider,
249+
stopDraggingFrameSlider,
213250
};
214251
},
215252
});
@@ -220,6 +257,39 @@ export default defineComponent({
220257
<v-card-text v-if="loaded">
221258
<v-row dense align="center" class="icon-row mb-2">
222259
<v-col class="d-flex align-center gap-2">
260+
<v-menu>
261+
<template #activator="{ props }">
262+
<v-badge
263+
:value="speed !== 1.0"
264+
color="#0277bd88"
265+
:content="`${speed}X`"
266+
overlap
267+
>
268+
<v-icon
269+
x-small
270+
v-bind="props"
271+
@click="setSpeed(1)"
272+
>
273+
mdi-speedometer
274+
</v-icon>
275+
</v-badge>
276+
</template>
277+
<v-card style="overflow:hidden; width:90px;">
278+
<v-slider
279+
:model-value="speed"
280+
min="0"
281+
max="6"
282+
step="1"
283+
:ticks="speedTicks"
284+
show-ticks="always"
285+
:tick-size="4"
286+
style="font-size:0.75em;"
287+
direction="vertical"
288+
@end="setSpeed($event)"
289+
/>
290+
</v-card>
291+
</v-menu>
292+
223293
<v-btn icon variant="plain" size="small" @click="seekOffset(-frameId)">
224294
<v-icon>mdi-skip-backward</v-icon>
225295
</v-btn>
@@ -257,6 +327,8 @@ export default defineComponent({
257327
step="1"
258328
thumb-label
259329
:disabled="totalFrames === 0"
330+
@start="startDraggingFrameSlider()"
331+
@end="stopDraggingFrameSlider()"
260332
/>
261333
</v-row>
262334
<v-divider />
@@ -359,4 +431,7 @@ export default defineComponent({
359431
align-items: center;
360432
justify-content: center;
361433
}
434+
.badge-text {
435+
font-size: 0.75em;
436+
}
362437
</style>

client/src/map/fmvStore.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,12 @@ const createFMVStore = () => {
170170
ground_union: 'fill',
171171
};
172172

173+
const setPlaybackSpeed = (speed: number) => {
174+
if (state.videoElement) {
175+
state.videoElement.playbackRate = speed;
176+
}
177+
};
178+
173179
return {
174180
...toRefs(state),
175181
videoData,
@@ -182,6 +188,7 @@ const createFMVStore = () => {
182188
seekOffset,
183189
seekToFrame,
184190
setVideoState,
191+
setPlaybackSpeed,
185192
};
186193
};
187194

@@ -223,6 +230,7 @@ export interface FMVStore {
223230

224231
setVideoSource: (baseSource: VideoSource) => void;
225232
setVideoFrame: (frame: number) => void;
233+
setPlaybackSpeed: (speed: number) => void;
226234
seekOffset: (offset: number) => void;
227235
seekToFrame: (offset: number) => void;
228236
getFMVLayerInfo: (id: number) => Promise<void>;

client/src/map/mapFMVLayer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ const updateFMVVideoMapping = (layer: FMVLayer) => {
407407
}
408408
if (fmvStore.lockZoom.value) {
409409
const bounds = boundsToBBoxWithMultiplier(coordinates, fmvStore.zoomBounds.value);
410-
internalMap.value.fitBounds(bounds, { linear: false });
410+
internalMap.value.fitBounds(bounds, { linear: false, maxDuration: 0, animate: false });
411411
}
412412
}
413413
};

client/src/types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -947,7 +947,9 @@ export interface FMVLayer extends AbstractMapLayer {
947947
export interface FMVLayerData {
948948
name: string;
949949
bbox:[number, number, number, number]; // [xmin, ymin, xmax, ymax]
950-
frameIdToBBox: Record<number, [[number, number], [number, number], [number, number], [number, number]]>; // Maps frame ID to bounding box [xmin, ymin, xmax, ymax]
950+
frameIdToBBox: Record<
951+
number, [[number, number], [number, number], [number, number], [number, number]]
952+
>; // Maps frame ID to bounding box [xmin, ymin, xmax, ymax]
951953
fmvVideoUrl: string; // URL to the FMV video file
952954
fmvFps: number; // Frames per second of the FMV video
953955
fmvFrameCount: number; // Total number of frames in the FMV video

0 commit comments

Comments
 (0)