Skip to content

Commit

Permalink
feat(Webcam): add a optional overlay for IDEX calibration (#2053)
Browse files Browse the repository at this point in the history
  • Loading branch information
meteyou authored Dec 1, 2024
1 parent 34f3f08 commit 04433fc
Show file tree
Hide file tree
Showing 9 changed files with 227 additions and 8 deletions.
4 changes: 2 additions & 2 deletions src/assets/styles/page.css
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ body {
height: 100% !important;
}

.p-abs {
.position-absolute {
position: absolute !important;
}

.p-rel {
.position-relative {
position: relative !important;
}

Expand Down
8 changes: 4 additions & 4 deletions src/components/panels/ToolheadControls/CrossControl.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@
</v-col>
</v-row>
<v-row dense>
<v-col cols="3" class="p-rel">
<v-col cols="3" class="position-relative">
<v-btn
class="btnMinWidthAuto fill-width p-abs"
class="btnMinWidthAuto fill-width position-absolute"
style="top: -50%; width: calc(100% - 8px)"
:disabled="
!xAxisHomed ||
Expand All @@ -72,9 +72,9 @@
<v-icon>{{ mdiChevronDown }}</v-icon>
</v-btn>
</v-col>
<v-col cols="3" class="p-rel">
<v-col cols="3" class="position-relative">
<v-btn
class="btnMinWidthAuto fill-width p-abs"
class="btnMinWidthAuto fill-width position-absolute"
style="top: -50%; width: calc(100% - 8px)"
:disabled="
!xAxisHomed ||
Expand Down
98 changes: 98 additions & 0 deletions src/components/settings/Webcams/WebcamForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,58 @@
:label="$t('Settings.WebcamsTab.Vertically')" />
</v-col>
</v-row>
<template v-if="nozzleCrosshairAvialable">
<v-row>
<v-col class="pt-3 pb-3">
<div class="v-label v-label--active theme--dark text-subtitle-1">
{{ $t('Settings.WebcamsTab.NozzleCrosshair') }}:
</div>
</v-col>
</v-row>
<v-row class="mt-0">
<v-col class="py-0">
<v-checkbox
v-model="nozzleCrosshair"
class="mt-1"
hide-details
:label="$t('Settings.WebcamsTab.Enable')" />
</v-col>
<v-col v-if="nozzleCrosshair" class="py-0">
<v-menu bottom left offset-y :close-on-content-click="false">
<template #activator="{ on, attrs }">
<v-btn
v-bind="attrs"
:color="nozzleCrosshairColor"
class="minwidth-0 px-5"
small
v-on="on" />
</template>
<v-color-picker
:value="nozzleCrosshairColor"
hide-mode-switch
mode="rgba"
@update:color="updateLogoColor" />
</v-menu>
<div
class="v-label v-label--active theme--dark text-subtitle-1 d-inline-block ml-2 mt-2">
{{ $t('Settings.WebcamsTab.Color') }}
</div>
</v-col>
</v-row>
<v-row v-if="nozzleCrosshair">
<v-col>
<v-slider
v-model="nozzleCrosshairSize"
:max="1"
:min="0.01"
:step="0.01"
thumb-label
thumb-size="24"
hide-details
:label="$t('Settings.WebcamsTab.Size')" />
</v-col>
</v-row>
</template>
</v-col>
<v-col class="col-12 col-sm-6 text-center" align-self="center">
<webcam-wrapper :webcam="webcam" page="settings" />
Expand Down Expand Up @@ -311,6 +363,52 @@ export default class WebcamForm extends Mixins(BaseMixin, WebcamMixin) {
this.webcam.extra_data.enableAudio = newVal
}
get nozzleCrosshairAvialable() {
return ['mjpegstreamer', 'mjpegstreamer-adaptive', 'webrtc-camerastreamer'].includes(this.webcam.service)
}
get nozzleCrosshair() {
return this.webcam.extra_data?.nozzleCrosshair ?? false
}
set nozzleCrosshair(newVal) {
const extraData = { ...(this.webcam.extra_data ?? {}) }
extraData.nozzleCrosshair = newVal
this.webcam.extra_data = extraData
}
get nozzleCrosshairColor() {
return this.webcam.extra_data?.nozzleCrosshairColor ?? '#ff0000'
}
set nozzleCrosshairColor(newVal: string) {
const extraData = { ...(this.webcam.extra_data ?? {}) }
extraData.nozzleCrosshairColor = newVal
this.webcam.extra_data = extraData
}
updateLogoColor(color: string | { hex: string }) {
if (typeof color === 'object') {
this.nozzleCrosshairColor = color.hex
return
}
this.nozzleCrosshairColor = color
}
get nozzleCrosshairSize() {
return this.webcam.extra_data?.nozzleCrosshairSize ?? 0.1
}
set nozzleCrosshairSize(newVal: number) {
const extraData = { ...(this.webcam.extra_data ?? {}) }
extraData.nozzleCrosshairSize = newVal
this.webcam.extra_data = extraData
}
mounted() {
this.oldWebcamName = this.webcam.name
}
Expand Down
94 changes: 94 additions & 0 deletions src/components/webcams/WebcamNozzleCrosshair.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<template>
<div ref="container" class="crosshair-container">
<div class="line horizontal" :style="styleLines" />
<div class="line vertical" :style="styleLines" />
<div class="circle" :style="styleCircle" />
<resize-observer @notify="handleResize" />
</div>
</template>

<script lang="ts">
import Component from 'vue-class-component'
import { Mixins, Prop, Ref } from 'vue-property-decorator'
import BaseMixin from '@/components/mixins/base'
import { GuiWebcamStateWebcam } from '@/store/gui/webcams/types'
@Component
export default class WebcamWrapper extends Mixins(BaseMixin) {
@Prop({ type: Object, required: true }) webcam!: GuiWebcamStateWebcam
@Ref() container!: HTMLDivElement
clientHeight = 0
get color() {
return this.webcam.extra_data?.nozzleCrosshairColor ?? '#ff0000'
}
get styleLines() {
return {
backgroundColor: this.color,
}
}
get styleCircle() {
const nozzleCrosshairSize = this.webcam.extra_data?.nozzleCrosshairSize ?? 0.1
const size = this.clientHeight * nozzleCrosshairSize
return {
borderColor: this.color,
width: `${size}px`,
height: `${size}px`,
marginLeft: `-${size / 2}px`,
marginTop: `-${size / 2}px`,
}
}
mounted() {
this.handleResize()
}
handleResize() {
this.$nextTick(() => {
this.clientHeight = this.container.clientHeight
})
}
}
</script>

<style scoped>
.crosshair-container {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.line {
position: absolute;
background-color: #ff0000;
}
.horizontal {
height: 1px;
top: 50%;
left: 0;
right: 0;
}
.vertical {
left: 50%;
top: 0;
bottom: 0;
width: 1px;
}
.circle {
position: absolute;
border: 1px solid #ff0000;
border-radius: 50%;
box-sizing: border-box;
top: 50%;
left: 50%;
}
</style>
7 changes: 7 additions & 0 deletions src/components/webcams/streamers/Mjpegstreamer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<span v-if="showFpsCounter && status === 'connected'" class="webcamFpsOutput">
{{ $t('Panels.WebcamPanel.FPS') }}: {{ fpsOutput }}
</span>
<webcam-nozzle-crosshair v-if="showNozzleCrosshair" :webcam="camSettings" />
<v-row v-if="status !== 'connected'">
<v-col class="_webcam_mjpegstreamer_output text-center d-flex flex-column justify-center align-center">
<v-progress-circular v-if="status === 'connecting'" indeterminate color="primary" class="mb-3" />
Expand Down Expand Up @@ -100,6 +101,12 @@ export default class Mjpegstreamer extends Mixins(BaseMixin, WebcamMixin) {
return this.$store.getters['gui/getPanelExpand']('webcam-panel', this.viewport) ?? false
}
get showNozzleCrosshair() {
const nozzleCrosshair = this.camSettings.extra_data?.nozzleCrosshair ?? false
return nozzleCrosshair && this.status === 'connected'
}
// start or stop the video when the expanded state changes
@Watch('expanded', { immediate: true })
expandChanged(newExpanded: boolean): void {
Expand Down
7 changes: 7 additions & 0 deletions src/components/webcams/streamers/MjpegstreamerAdaptive.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<span v-if="status === 'connected' && showFpsCounter" class="webcamFpsOutput">
{{ $t('Panels.WebcamPanel.FPS') }}: {{ fpsOutput }}
</span>
<webcam-nozzle-crosshair v-if="showNozzleCrosshair" :webcam="camSettings" />
<v-row v-if="status !== 'connected'">
<v-col class="_webcam_mjpegstreamer_output text-center d-flex flex-column justify-center align-center">
<v-progress-circular v-if="status === 'connecting'" indeterminate color="primary" class="mb-3" />
Expand Down Expand Up @@ -101,6 +102,12 @@ export default class MjpegstreamerAdaptive extends Mixins(BaseMixin, WebcamMixin
return this.isVisibleDocument && this.isVisibleViewport
}
get showNozzleCrosshair() {
const nozzleCrosshair = this.camSettings.extra_data?.nozzleCrosshair ?? false
return nozzleCrosshair && this.status === 'connected'
}
mounted() {
document.addEventListener('visibilitychange', this.documentVisibilityChanged)
}
Expand Down
10 changes: 8 additions & 2 deletions src/components/webcams/streamers/WebrtcCameraStreamer.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div>
<div class="position-relative d-flex">
<video
v-show="status === 'connected'"
ref="stream"
Expand All @@ -8,6 +8,7 @@
autoplay
muted
playsinline />
<webcam-nozzle-crosshair v-if="nozzleCrosshair" :webcam="camSettings" />
<v-row v-if="status !== 'connected'">
<v-col class="_webcam_webrtc_output text-center d-flex flex-column justify-center align-center">
<v-progress-circular v-if="status === 'connecting'" indeterminate color="primary" class="mb-3" />
Expand All @@ -23,14 +24,15 @@ import BaseMixin from '@/components/mixins/base'
import { GuiWebcamStateWebcam } from '@/store/gui/webcams/types'
import WebcamMixin from '@/components/mixins/webcam'
import { capitalize } from '@/plugins/helpers'
import WebcamNozzleCrosshair from '@/components/webcams/WebcamNozzleCrosshair.vue'
interface CameraStreamerResponse extends RTCSessionDescriptionInit {
id: string
iceServers?: RTCIceServer[]
}
@Component({
methods: { capitalize },
components: { WebcamNozzleCrosshair },
})
export default class WebrtcCameraStreamer extends Mixins(BaseMixin, WebcamMixin) {
capitalize = capitalize
Expand Down Expand Up @@ -65,6 +67,10 @@ export default class WebrtcCameraStreamer extends Mixins(BaseMixin, WebcamMixin)
return output
}
get nozzleCrosshair() {
return this.camSettings.extra_data?.nozzleCrosshair ?? false
}
get expanded(): boolean {
if (this.page !== 'dashboard') return true
Expand Down
4 changes: 4 additions & 0 deletions src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1292,9 +1292,11 @@
"Update": "update",
"WebcamsTab": {
"AddWebcam": "add webcam",
"Color": "Color",
"CreateWebcam": "Create Webcam",
"EditCrowsnestConf": "Edit crowsnest.conf",
"EditWebcam": "Edit Webcam",
"Enable": "Enable",
"EnableAudio": "Enable audio",
"FlipWebcam": "Flip webcam image:",
"HideFps": "Hide FPS counter",
Expand All @@ -1314,10 +1316,12 @@
"MjpegstreamerAdaptive": "Adaptive MJPEG-Streamer (experimental)",
"Name": "Name",
"NameAlreadyExists": "Name already exists",
"NozzleCrosshair": "Nozzle Crosshair",
"Required": "required",
"Rotate": "Rotate",
"SaveWebcam": "Save Webcam",
"Service": "Service",
"Size": "Size",
"TargetFPS": "Target FPS",
"UpdateWebcam": "Update Webcam",
"UrlSnapshot": "URL Snapshot",
Expand Down
3 changes: 3 additions & 0 deletions src/store/gui/webcams/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ export interface GuiWebcamStateWebcam {
extra_data?: {
enableAudio?: boolean
hideFps?: boolean
nozzleCrosshair?: boolean
nozzleCrosshairColor?: string
nozzleCrosshairSize?: number
}
source?: 'config' | 'database'
}

0 comments on commit 04433fc

Please sign in to comment.