forked from platypush/platypush
[Camera UI] Dynamic fullscreen support.
This commit is contained in:
parent
3fddf67949
commit
b69e950076
2 changed files with 87 additions and 25 deletions
|
@ -1,10 +1,17 @@
|
||||||
<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_}"
|
||||||
|
ref="cameraContainer">
|
||||||
|
<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>
|
<div class="no-frame" v-if="!streaming && !capturing && !captured">The camera is not active</div>
|
||||||
<img class="frame" :src="url" ref="frame" alt="">
|
<img class="frame" :src="url" ref="frame" alt="">
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<div class="left">
|
<div class="left">
|
||||||
|
@ -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() {
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in a new issue