[Camera UI] Dynamic fullscreen support.

This commit is contained in:
Fabio Manganiello 2024-07-20 02:23:56 +02:00
parent 3fddf67949
commit b69e950076
Signed by untrusted user: blacklight
GPG key ID: D90FBA7F76362774
2 changed files with 87 additions and 25 deletions

View file

@ -1,9 +1,16 @@
<template> <template>
<div class="camera"> <div class="camera" ref="cameraRoot">
<div class="camera-container"> <div class="camera-container"
<div class="frame-container" ref="frameContainer"> :class="{fullscreen: fullscreen_}"
<div class="no-frame" v-if="!streaming && !capturing && !captured">The camera is not active</div> ref="cameraContainer">
<img class="frame" :src="url" ref="frame" alt=""> <div class="frame-canvas" ref="frameCanvas">
<div class="frame-container"
:class="{vertical: isCameraVertical, horizontal: !isCameraVertical}"
:style="{aspectRatio: aspectRatio}"
ref="frameContainer">
<div class="no-frame" v-if="!streaming && !capturing && !captured">The camera is not active</div>
<img class="frame" :src="url" ref="frame" alt="">
</div>
</div> </div>
<div class="controls"> <div class="controls">
@ -34,6 +41,14 @@
<button type="button" @click="$refs.paramsModal.show()" title="Settings"> <button type="button" @click="$refs.paramsModal.show()" title="Settings">
<i class="fas fa-cog" /> <i class="fas fa-cog" />
</button> </button>
<button type="button"
:title="fullscreen_ ? 'Exit fullscreen' : 'Fullscreen'"
@click="fullscreen_ = !fullscreen_"
v-if="!fullscreen">
<i class="fas fa-expand" v-if="!fullscreen_" />
<i class="fas fa-compress" v-else />
</button>
</div> </div>
</div> </div>
</div> </div>
@ -104,7 +119,7 @@
<input name="grayscale" type="checkbox" v-model="attrs.grayscale" @change="onGrayscaleChanged"/> <input name="grayscale" type="checkbox" v-model="attrs.grayscale" @change="onGrayscaleChanged"/>
</label> </label>
<Slot /> <slot />
</div> </div>
</Modal> </Modal>
</div> </div>
@ -118,12 +133,6 @@ export default {
name: "Camera", name: "Camera",
components: {Modal}, components: {Modal},
mixins: [CameraMixin], mixins: [CameraMixin],
props: {
cameraPlugin: {
type: String,
required: true,
},
},
computed: { computed: {
fullURL() { fullURL() {

View file

@ -6,6 +6,11 @@ export default {
mixins: [Utils], mixins: [Utils],
props: { props: {
fullscreen: {
type: Boolean,
default: false,
},
cameraPlugin: { cameraPlugin: {
type: String, type: String,
required: true, required: true,
@ -17,9 +22,11 @@ export default {
streaming: false, streaming: false,
capturing: false, capturing: false,
captured: false, captured: false,
fullscreen_: false,
audioOn: false, audioOn: false,
url: null, url: null,
attrs: {}, attrs: {},
resizeObserver: null,
} }
}, },
@ -37,6 +44,20 @@ export default {
grayscale: parseInt(0 + this.attrs.grayscale), grayscale: parseInt(0 + this.attrs.grayscale),
} }
}, },
aspectRatio() {
if (!this.attrs?.resolution)
return 1
return `${this.attrs.resolution[0]}/${this.attrs.resolution[1]}`
},
isCameraVertical() {
if (!this.attrs?.resolution)
return false
return this.attrs.resolution[1] > this.attrs.resolution[0]
},
}, },
methods: { methods: {
@ -82,25 +103,41 @@ export default {
}, },
onDeviceChanged() {}, onDeviceChanged() {},
onFlipChanged() {},
onFlipChanged() {
this.onSizeChanged()
},
onSizeChanged() { onSizeChanged() {
const degToRad = (deg) => (deg * Math.PI)/180 const degToRad = (deg) => (deg * Math.PI)/180
const rot = degToRad(this.params.rotate) const rot = degToRad(this.params.rotate)
let width = Math.round(this.params.scale_x * Math.abs(this.params.resolution[0] * Math.cos(rot) + this.params.resolution[1] * Math.sin(rot))) const outerWidth = this.$refs.frameContainer.parentElement.offsetWidth
let height = Math.round(this.params.scale_y * Math.abs(this.params.resolution[0] * Math.sin(rot) + this.params.resolution[1] * Math.cos(rot))) const outerHeight = this.$refs.frameContainer.parentElement.offsetHeight
if (width > window.innerWidth) { let width = (
height = Math.round(height * (window.innerWidth / width)) Math.round(
width = window.innerWidth this.params.scale_x * Math.abs(this.params.resolution[0] * Math.cos(rot) + this.params.resolution[1] * Math.sin(rot))
) + 'px'
)
let height = (
Math.round(
this.params.scale_y * Math.abs(this.params.resolution[0] * Math.sin(rot) + this.params.resolution[1] * Math.cos(rot))
) + 'px'
)
if (this.fullscreen_) {
if (this.params.resolution[0] > this.params.resolution[1]) {
width = '100%'
height = (outerHeight * (this.params.resolution[1] / this.params.resolution[0])) + 'px'
} else {
height = '100%'
width = (outerWidth * (this.params.resolution[0] / this.params.resolution[1])) + 'px'
}
} }
if (height > window.innerHeight) { this.$refs.frameContainer.style.width = width
width = Math.round(width * (window.innerHeight / height)) this.$refs.frameContainer.style.height = height
height = window.innerHeight
}
this.$refs.frameContainer.style.width = `${width}px`
this.$refs.frameContainer.style.height = `${height}px`
}, },
onFpsChanged() {}, onFpsChanged() {},
@ -133,6 +170,7 @@ export default {
}, },
mounted() { mounted() {
this.fullscreen_ = this.fullscreen
this.$refs.frame.addEventListener('load', this.onFrameLoaded) this.$refs.frame.addEventListener('load', this.onFrameLoaded)
this.onSizeChanged() this.onSizeChanged()
this.$watch(() => this.attrs.resolution, this.onSizeChanged) this.$watch(() => this.attrs.resolution, this.onSizeChanged)
@ -141,6 +179,21 @@ export default {
this.$watch(() => this.attrs.rotate, this.onSizeChanged) this.$watch(() => this.attrs.rotate, this.onSizeChanged)
this.$watch(() => this.attrs.scale_x, this.onSizeChanged) this.$watch(() => this.attrs.scale_x, this.onSizeChanged)
this.$watch(() => this.attrs.scale_y, this.onSizeChanged) this.$watch(() => this.attrs.scale_y, this.onSizeChanged)
const onOrientationOrSizeChange = () => {
this.onSizeChanged()
}
onOrientationOrSizeChange()
this.$nextTick(() => {
this.resizeObserver = new ResizeObserver(onOrientationOrSizeChange)
this.resizeObserver.observe(this.$refs?.frameContainer?.parentElement)
})
},
unmouted() {
this.resizeObserver?.disconnect()
}, },
} }
</script> </script>