Problem Description:
I’m working on a multi-camera widget with a fullscreen popup feature. The popup works perfectly, but I need the camera image to be zoomable (pinch-to-zoom) while maintaining automatic refresh.
Current Working Code:
# Current f7-popup implementation (works but NOT zoomable)
- component: f7-popup
config:
backdrop: true
closeByBackdropClick: true
closeByOutsideClick: true
closeOnEscape: true
id: fullscreenCamera
opened: =vars.fullscreenOpen === 'true'
style:
background: black
z-index: 10000
slots:
default:
- component: f7-block
config:
style:
align-items: center
background: black
display: flex
height: 100vh
justify-content: center
margin: 0
padding: 0
position: relative
width: 100vw
slots:
default:
- component: oh-image-card
config:
item: "= vars.activeCamera === 1 || vars.activeCamera === undefined ?
props.camera1ImageItem : vars.activeCamera === 2 ?
props.camera2ImageItem : vars.activeCamera === 3 ?
props.camera3ImageItem : vars.activeCamera === 4 ?
props.camera4ImageItem : vars.activeCamera === 5 ?
props.camera5ImageItem : vars.activeCamera === 6 ?
props.camera6ImageItem : vars.activeCamera === 7 ?
props.camera7ImageItem : props.camera1ImageItem"
noBorder: true
noShadow: true
refreshInterval: =props.refreshRate
style:
background: transparent
height: 100%
object-fit: contain
width: 100%
- component: oh-button
config:
action: variable
actionVariable: fullscreenOpen
actionVariableValue: "false"
iconColor: red
iconF7: xmark
iconSize: 28
style:
position: absolute
right: 0px
top: 0px
z-index: 10001
What I’ve Tried:
Attempt 1: Using f7-photo-browser with action: photos
# This approach makes image zoomable but NO refresh functionality
- component: oh-button
config:
action: photos
actionPhotos:
- "=items[vars.activeCamera === 1 ? props.camera1ImageItem :
vars.activeCamera === 2 ? props.camera2ImageItem :
props.camera1ImageItem].state"
style:
# button styles...
Result: Image is zoomable,
No automatic refresh (static image)
Attempt 2: Using f7-photo-browser component directly
# Tried embedding f7-photo-browser in popup
- component: f7-photo-browser
config:
photos:
- "=items[props.camera1ImageItem].state"
type: popup
# other configs...
Result: Doesn’t work as expected in widget context
Attempt 3: CSS transform for zoom
# Tried adding CSS transforms to oh-image-card
style:
transform-origin: center
transition: transform 0.3s ease
# touch events don't work properly
Result: No proper touch/pinch zoom support
Requirements:
Zoomable image (pinch-to-zoom, pan when zoomed)
Automatic refresh (e.g., every 1000ms)
Fullscreen popup overlay
Close button functionality
Dynamic camera switching (7 different cameras)
Questions:
- Is there a way to make
oh-image-card
zoomable withinf7-popup
? - Can
f7-photo-browser
be configured to auto-refresh images? - Are there alternative approaches using other F7 components?
- CSS-only solutions that work with touch devices?
Any suggestions or working examples would be greatly appreciated!
and by the way here is the full actual code:
uid: CameraSnapshotHistory_auto_v3
tags: []
props:
parameters:
- label: Kamera 1 Equipment
name: camera1
required: false
type: TEXT
- label: Kamera 1 Name
name: camera1Name
required: false
type: TEXT
- label: Kamera 1 Base URL
name: camera1BaseURL
required: false
type: TEXT
- context: item
label: Kamera 1 Image Item
name: camera1ImageItem
required: false
type: TEXT
- context: item
label: Kamera 1 PTZ Preset Item
name: camera1PtzPresetItem
required: false
type: TEXT
- description: "Format: 1=Option1,2=Option2,3=Option3"
label: Kamera 1 PTZ Preset Options
name: camera1PtzPresetOptions
required: false
type: TEXT
- context: item
label: Kamera 1 PTZ Auto Reset Item
name: camera1PtzAutoResetItem
required: false
type: TEXT
- description: "Format: 1=Auto-Reset,2=Kamerafahrt,3=Manuell"
label: Kamera 1 PTZ Auto Reset Options
name: camera1PtzAutoResetOptions
required: false
type: TEXT
- label: Kamera 2 Equipment
name: camera2
required: false
type: TEXT
- label: Kamera 2 Name
name: camera2Name
required: false
type: TEXT
- label: Kamera 2 Base URL
name: camera2BaseURL
required: false
type: TEXT
- context: item
label: Kamera 2 Image Item
name: camera2ImageItem
required: false
type: TEXT
- context: item
label: Kamera 2 PTZ Preset Item
name: camera2PtzPresetItem
required: false
type: TEXT
- description: "Format: 1=Option1,2=Option2,3=Option3"
label: Kamera 2 PTZ Preset Options
name: camera2PtzPresetOptions
required: false
type: TEXT
- context: item
label: Kamera 2 PTZ Auto Reset Item
name: camera2PtzAutoResetItem
required: false
type: TEXT
- description: "Format: 1=Auto-Reset,2=Kamerafahrt,3=Manuell"
label: Kamera 2 PTZ Auto Reset Options
name: camera2PtzAutoResetOptions
required: false
type: TEXT
- label: Kamera 3 Equipment
name: camera3
required: false
type: TEXT
- label: Kamera 3 Name
name: camera3Name
required: false
type: TEXT
- label: Kamera 3 Base URL
name: camera3BaseURL
required: false
type: TEXT
- context: item
label: Kamera 3 Image Item
name: camera3ImageItem
required: false
type: TEXT
- context: item
label: Kamera 3 PTZ Preset Item
name: camera3PtzPresetItem
required: false
type: TEXT
- description: "Format: 1=Option1,2=Option2,3=Option3"
label: Kamera 3 PTZ Preset Options
name: camera3PtzPresetOptions
required: false
type: TEXT
- context: item
label: Kamera 3 PTZ Auto Reset Item
name: camera3PtzAutoResetItem
required: false
type: TEXT
- description: "Format: 1=Auto-Reset,2=Kamerafahrt,3=Manuell"
label: Kamera 3 PTZ Auto Reset Options
name: camera3PtzAutoResetOptions
required: false
type: TEXT
- label: Kamera 4 Equipment
name: camera4
required: false
type: TEXT
- label: Kamera 4 Name
name: camera4Name
required: false
type: TEXT
- label: Kamera 4 Base URL
name: camera4BaseURL
required: false
type: TEXT
- context: item
label: Kamera 4 Image Item
name: camera4ImageItem
required: false
type: TEXT
- context: item
label: Kamera 4 PTZ Preset Item
name: camera4PtzPresetItem
required: false
type: TEXT
- description: "Format: 1=Option1,2=Option2,3=Option3"
label: Kamera 4 PTZ Preset Options
name: camera4PtzPresetOptions
required: false
type: TEXT
- context: item
label: Kamera 4 PTZ Auto Reset Item
name: camera4PtzAutoResetItem
required: false
type: TEXT
- description: "Format: 1=Auto-Reset,2=Kamerafahrt,3=Manuell"
label: Kamera 4 PTZ Auto Reset Options
name: camera4PtzAutoResetOptions
required: false
type: TEXT
- label: Kamera 5 Equipment
name: camera5
required: false
type: TEXT
- label: Kamera 5 Name
name: camera5Name
required: false
type: TEXT
- label: Kamera 5 Base URL
name: camera5BaseURL
required: false
type: TEXT
- context: item
label: Kamera 5 Image Item
name: camera5ImageItem
required: false
type: TEXT
- context: item
label: Kamera 5 PTZ Preset Item
name: camera5PtzPresetItem
required: false
type: TEXT
- description: "Format: 1=Option1,2=Option2,3=Option3"
label: Kamera 5 PTZ Preset Options
name: camera5PtzPresetOptions
required: false
type: TEXT
- context: item
label: Kamera 5 PTZ Auto Reset Item
name: camera5PtzAutoResetItem
required: false
type: TEXT
- description: "Format: 1=Auto-Reset,2=Kamerafahrt,3=Manuell"
label: Kamera 5 PTZ Auto Reset Options
name: camera5PtzAutoResetOptions
required: false
type: TEXT
- label: Kamera 6 Equipment
name: camera6
required: false
type: TEXT
- label: Kamera 6 Name
name: camera6Name
required: false
type: TEXT
- label: Kamera 6 Base URL
name: camera6BaseURL
required: false
type: TEXT
- context: item
label: Kamera 6 Image Item
name: camera6ImageItem
required: false
type: TEXT
- context: item
label: Kamera 6 PTZ Preset Item
name: camera6PtzPresetItem
required: false
type: TEXT
- description: "Format: 1=Option1,2=Option2,3=Option3"
label: Kamera 6 PTZ Preset Options
name: camera6PtzPresetOptions
required: false
type: TEXT
- context: item
label: Kamera 6 PTZ Auto Reset Item
name: camera6PtzAutoResetItem
required: false
type: TEXT
- description: "Format: 1=Auto-Reset,2=Kamerafahrt,3=Manuell"
label: Kamera 6 PTZ Auto Reset Options
name: camera6PtzAutoResetOptions
required: false
type: TEXT
- label: Kamera 7 Equipment
name: camera7
required: false
type: TEXT
- label: Kamera 7 Name
name: camera7Name
required: false
type: TEXT
- label: Kamera 7 Base URL
name: camera7BaseURL
required: false
type: TEXT
- context: item
label: Kamera 7 Image Item
name: camera7ImageItem
required: false
type: TEXT
- context: item
label: Kamera 7 PTZ Preset Item
name: camera7PtzPresetItem
required: false
type: TEXT
- description: "Format: 1=Option1,2=Option2,3=Option3"
label: Kamera 7 PTZ Preset Options
name: camera7PtzPresetOptions
required: false
type: TEXT
- context: item
label: Kamera 7 PTZ Auto Reset Item
name: camera7PtzAutoResetItem
required: false
type: TEXT
- description: "Format: 1=Auto-Reset,2=Kamerafahrt,3=Manuell"
label: Kamera 7 PTZ Auto Reset Options
name: camera7PtzAutoResetOptions
required: false
type: TEXT
- description: Refresh rate in milliseconds (e.g., 1000 for 1 second)
label: Refresh Rate
name: refreshRate
required: true
type: INTEGER
timestamp: Aug 11, 2025, 1:29:04 PM
component: f7-card
config:
key: "=((vars.selected || 0) === undefined) ? Math.random() : Math.random() +
(vars.selected || 0)"
noBorder: true
noShadow: true
style:
--f7-card-margin-horizontal: 5px
--f7-card-margin-vertical: 5px
background: var(--f7-theme-color)
border-radius: var(--f7-card-expandable-border-radius)
height: auto
max-height: "=vars.ptzExpanded === 'true' && vars.archive !== 2 ? 'none' : 'auto'"
overflow: hidden
transition: all 0.3s ease
width: auto
slots:
default:
- component: f7-block
config:
style:
background: var(--f7-theme-color)
border-radius: 0px
color: "=(themeOptions.dark == 'dark') ? 'white' : 'black'"
margin: 0
padding: 8px
slots:
default:
- component: f7-swiper
config:
params:
direction: horizontal
freeMode: true
mousewheel: true
scrollbar:
draggable: true
el: .swiper-scrollbar
slidesPerView: auto
style:
height: 40px
slots:
default:
- component: f7-swiper-slide
config:
style:
padding: 0 4px
width: auto
visible: =!!(props.camera1 && props.camera1Name)
slots:
default:
- component: oh-button
config:
action: variable
actionVariable: activeCamera
actionVariableValue: 1
style:
align-items: center
background: "=vars.activeCamera === 1 || vars.activeCamera === undefined ?
'var(--f7-theme-color-shade)' :
'rgba(255,255,255,0.2)'"
border: "=vars.activeCamera === 1 || vars.activeCamera === undefined ? '2px
solid white' : '1px solid rgba(255,255,255,0.3)'"
border-radius: 6px
color: white
display: flex
font-size: 13px
font-weight: "=vars.activeCamera === 1 || vars.activeCamera === undefined ?
'bold' : 'normal'"
justify-content: center
padding: 4px 8px
text-align: center
text: =props.camera1Name
- component: f7-swiper-slide
config:
style:
padding: 0 4px
width: auto
visible: =!!(props.camera2 && props.camera2Name)
slots:
default:
- component: oh-button
config:
action: variable
actionVariable: activeCamera
actionVariableValue: 2
style:
align-items: center
background: "=vars.activeCamera === 2 ? 'var(--f7-theme-color-shade)' :
'rgba(255,255,255,0.2)'"
border: "=vars.activeCamera === 2 ? '2px solid white' : '1px solid
rgba(255,255,255,0.3)'"
border-radius: 6px
color: white
display: flex
font-size: 13px
font-weight: "=vars.activeCamera === 2 ? 'bold' : 'normal'"
justify-content: center
padding: 4px 8px
text-align: center
text: =props.camera2Name
- component: f7-swiper-slide
config:
style:
padding: 0 4px
width: auto
visible: =!!(props.camera3 && props.camera3Name)
slots:
default:
- component: oh-button
config:
action: variable
actionVariable: activeCamera
actionVariableValue: 3
style:
align-items: center
background: "=vars.activeCamera === 3 ? 'var(--f7-theme-color-shade)' :
'rgba(255,255,255,0.2)'"
border: "=vars.activeCamera === 3 ? '2px solid white' : '1px solid
rgba(255,255,255,0.3)'"
border-radius: 6px
color: white
display: flex
font-size: 13px
font-weight: "=vars.activeCamera === 3 ? 'bold' : 'normal'"
justify-content: center
padding: 4px 8px
text-align: center
text: =props.camera3Name
- component: f7-swiper-slide
config:
style:
padding: 0 4px
width: auto
visible: =!!(props.camera4 && props.camera4Name)
slots:
default:
- component: oh-button
config:
action: variable
actionVariable: activeCamera
actionVariableValue: 4
style:
align-items: center
background: "=vars.activeCamera === 4 ? 'var(--f7-theme-color-shade)' :
'rgba(255,255,255,0.2)'"
border: "=vars.activeCamera === 4 ? '2px solid white' : '1px solid
rgba(255,255,255,0.3)'"
border-radius: 6px
color: white
display: flex
font-size: 13px
font-weight: "=vars.activeCamera === 4 ? 'bold' : 'normal'"
justify-content: center
padding: 4px 8px
text-align: center
text: =props.camera4Name
- component: f7-swiper-slide
config:
style:
padding: 0 4px
width: auto
visible: =!!(props.camera5 && props.camera5Name)
slots:
default:
- component: oh-button
config:
action: variable
actionVariable: activeCamera
actionVariableValue: 5
style:
align-items: center
background: "=vars.activeCamera === 5 ? 'var(--f7-theme-color-shade)' :
'rgba(255,255,255,0.2)'"
border: "=vars.activeCamera === 5 ? '2px solid white' : '1px solid
rgba(255,255,255,0.3)'"
border-radius: 6px
color: white
display: flex
font-size: 13px
font-weight: "=vars.activeCamera === 5 ? 'bold' : 'normal'"
justify-content: center
padding: 4px 8px
text-align: center
text: =props.camera5Name
- component: f7-swiper-slide
config:
style:
padding: 0 4px
width: auto
visible: =!!(props.camera6 && props.camera6Name)
slots:
default:
- component: oh-button
config:
action: variable
actionVariable: activeCamera
actionVariableValue: 6
style:
align-items: center
background: "=vars.activeCamera === 6 ? 'var(--f7-theme-color-shade)' :
'rgba(255,255,255,0.2)'"
border: "=vars.activeCamera === 6 ? '2px solid white' : '1px solid
rgba(255,255,255,0.3)'"
border-radius: 6px
color: white
display: flex
font-size: 13px
font-weight: "=vars.activeCamera === 6 ? 'bold' : 'normal'"
justify-content: center
padding: 4px 8px
text-align: center
text: =props.camera6Name
- component: f7-swiper-slide
config:
style:
padding: 0 4px
width: auto
visible: =!!(props.camera7 && props.camera7Name)
slots:
default:
- component: oh-button
config:
action: variable
actionVariable: activeCamera
actionVariableValue: 7
style:
align-items: center
background: "=vars.activeCamera === 7 ? 'var(--f7-theme-color-shade)' :
'rgba(255,255,255,0.2)'"
border: "=vars.activeCamera === 7 ? '2px solid white' : '1px solid
rgba(255,255,255,0.3)'"
border-radius: 6px
color: white
display: flex
font-size: 13px
font-weight: "=vars.activeCamera === 7 ? 'bold' : 'normal'"
justify-content: center
padding: 4px 8px
text-align: center
text: =props.camera7Name
- component: f7-block
config:
style:
background: transparent
margin: 0
overflow: hidden
padding: 0
position: relative
slots:
default:
- component: oh-video-card
config:
hideControls: false
noBorder: true
noShadow: true
startManually: false
style:
background: transparent
border-radius: 0px
display: block
height: auto
margin: 0px
max-width: 100%
object-fit: contain
padding: 0px
width: 100%
url: "= (vars.activeCamera === 1 || vars.activeCamera === undefined ?
props.camera1BaseURL : vars.activeCamera === 2 ?
props.camera2BaseURL : vars.activeCamera === 3 ?
props.camera3BaseURL : vars.activeCamera === 4 ?
props.camera4BaseURL : vars.activeCamera === 5 ?
props.camera5BaseURL : vars.activeCamera === 6 ?
props.camera6BaseURL : vars.activeCamera === 7 ?
props.camera7BaseURL : props.camera1BaseURL) +
items[(vars.activeCamera === 1 || vars.activeCamera ===
undefined ? props.camera1 : vars.activeCamera === 2 ?
props.camera2 : vars.activeCamera === 3 ? props.camera3 :
vars.activeCamera === 4 ? props.camera4 : vars.activeCamera ===
5 ? props.camera5 : vars.activeCamera === 6 ? props.camera6 :
vars.activeCamera === 7 ? props.camera7 : props.camera1) +
'_MP4_History'].state.split(',')[(vars.selected || 0)] + '.mp4'"
visible: =vars.archive == 2
- component: oh-image-card
config:
item: "= vars.activeCamera === 1 || vars.activeCamera === undefined ?
props.camera1ImageItem : vars.activeCamera === 2 ?
props.camera2ImageItem : vars.activeCamera === 3 ?
props.camera3ImageItem : vars.activeCamera === 4 ?
props.camera4ImageItem : vars.activeCamera === 5 ?
props.camera5ImageItem : vars.activeCamera === 6 ?
props.camera6ImageItem : vars.activeCamera === 7 ?
props.camera7ImageItem : props.camera1ImageItem"
noBorder: true
noShadow: true
refreshInterval: "=vars.fullscreenOpen === 'true' ? 0 : props.refreshRate"
style:
background: transparent
border-radius: 0px
display: block
height: auto
margin: 0px
max-width: 100%
object-fit: contain
padding: 0px
width: 100%
visible: =vars.archive != 2
- component: f7-row
config:
class: no-gap
noBorder: true
noShadow: true
style:
height: auto
position: absolute
top: 0px
width: 100%
z-index: 2
slots:
default:
- component: oh-button
config:
action: variable
actionVariable: archive
actionVariableValue: 2
iconColor: red
iconF7: folder
iconSize: 28
style:
margin: -2px
visible: "= items[(vars.activeCamera === 1 || vars.activeCamera === undefined ?
props.camera1 : vars.activeCamera === 2 ? props.camera2 :
vars.activeCamera === 3 ? props.camera3 :
vars.activeCamera === 4 ? props.camera4 :
vars.activeCamera === 5 ? props.camera5 :
vars.activeCamera === 6 ? props.camera6 :
vars.activeCamera === 7 ? props.camera7 : props.camera1) +
'_MP4_History'].state !== NULL && items[(vars.activeCamera
=== 1 || vars.activeCamera === undefined ? props.camera1 :
vars.activeCamera === 2 ? props.camera2 :
vars.activeCamera === 3 ? props.camera3 :
vars.activeCamera === 4 ? props.camera4 :
vars.activeCamera === 5 ? props.camera5 :
vars.activeCamera === 6 ? props.camera6 :
vars.activeCamera === 7 ? props.camera7 : props.camera1) +
'_MP4_History_Length'].state > 0 ? vars.archive !== 2 :
false"
z-index: 2
- component: oh-button
config:
action: variable
actionVariable: fullscreenOpen
actionVariableValue: "true"
iconColor: red
iconF7: viewfinder
iconSize: 28
style:
height: 32px
margin: -2px
position: absolute
right: 0px
top: 0px
width: 32px
z-index: 2
visible: =vars.archive !== 2
- component: Label
config:
style:
color: red
font-size: 9px
left: 14px
position: absolute
top: 6px
z-index: -1
text: =((vars.selected || 0)+1)
visible: =vars.archive == 2
- component: oh-button
config:
action: variable
actionVariable: archive
actionVariableValue: 1
iconColor: red
iconF7: videocam
iconSize: 28
style:
margin: -2px
visible: =(vars.archive == 2)
- component: oh-button
config:
action: variable
actionVariable: selected
actionVariableValue: "= items[(vars.activeCamera === 1 || vars.activeCamera ===
undefined ? props.camera1 : vars.activeCamera === 2 ?
props.camera2 : vars.activeCamera === 3 ? props.camera3 :
vars.activeCamera === 4 ? props.camera4 :
vars.activeCamera === 5 ? props.camera5 :
vars.activeCamera === 6 ? props.camera6 :
vars.activeCamera === 7 ? props.camera7 : props.camera1) +
'_MP4_History_Length'].state - 1"
iconColor: red
iconF7: backward_end
iconSize: 28
style:
margin: -2px
visible: "=vars.archive == 2 && items[(vars.activeCamera === 1 ||
vars.activeCamera === undefined ? props.camera1 :
vars.activeCamera === 2 ? props.camera2 :
vars.activeCamera === 3 ? props.camera3 :
vars.activeCamera === 4 ? props.camera4 :
vars.activeCamera === 5 ? props.camera5 :
vars.activeCamera === 6 ? props.camera6 :
vars.activeCamera === 7 ? props.camera7 : props.camera1) +
'_MP4_History_Length'].state > 0"
- component: oh-button
config:
action: variable
actionVariable: selected
actionVariableValue: "=((vars.selected || 0)+1 < items[(vars.activeCamera === 1
|| vars.activeCamera === undefined ? props.camera1 :
vars.activeCamera === 2 ? props.camera2 :
vars.activeCamera === 3 ? props.camera3 :
vars.activeCamera === 4 ? props.camera4 :
vars.activeCamera === 5 ? props.camera5 :
vars.activeCamera === 6 ? props.camera6 :
vars.activeCamera === 7 ? props.camera7 : props.camera1) +
'_MP4_History_Length'].state)?((vars.selected || 0)+1):(
items[(vars.activeCamera === 1 || vars.activeCamera ===
undefined ? props.camera1 : vars.activeCamera === 2 ?
props.camera2 : vars.activeCamera === 3 ? props.camera3 :
vars.activeCamera === 4 ? props.camera4 :
vars.activeCamera === 5 ? props.camera5 :
vars.activeCamera === 6 ? props.camera6 :
vars.activeCamera === 7 ? props.camera7 : props.camera1) +
'_MP4_History_Length'].state-1)"
iconColor: red
iconF7: arrowtriangle_left
iconSize: 28
style:
margin: -2px
visible: "=vars.archive == 2 && items[(vars.activeCamera === 1 ||
vars.activeCamera === undefined ? props.camera1 :
vars.activeCamera === 2 ? props.camera2 :
vars.activeCamera === 3 ? props.camera3 :
vars.activeCamera === 4 ? props.camera4 :
vars.activeCamera === 5 ? props.camera5 :
vars.activeCamera === 6 ? props.camera6 :
vars.activeCamera === 7 ? props.camera7 : props.camera1) +
'_MP4_History_Length'].state > 0"
- component: oh-button
config:
action: variable
actionVariable: selected
actionVariableValue: =((vars.selected || 0) != 0)?((vars.selected || 0)-1):(0)
iconColor: red
iconF7: arrowtriangle_right
iconSize: 28
style:
margin: -2px
visible: "=vars.archive == 2 && items[(vars.activeCamera === 1 ||
vars.activeCamera === undefined ? props.camera1 :
vars.activeCamera === 2 ? props.camera2 :
vars.activeCamera === 3 ? props.camera3 :
vars.activeCamera === 4 ? props.camera4 :
vars.activeCamera === 5 ? props.camera5 :
vars.activeCamera === 6 ? props.camera6 :
vars.activeCamera === 7 ? props.camera7 : props.camera1) +
'_MP4_History_Length'].state > 0"
- component: oh-button
config:
action: variable
actionVariable: selected
actionVariableValue: 0
iconColor: red
iconF7: forward_end
iconSize: 28
style:
margin: -2px
visible: "=vars.archive == 2 && items[(vars.activeCamera === 1 ||
vars.activeCamera === undefined ? props.camera1 :
vars.activeCamera === 2 ? props.camera2 :
vars.activeCamera === 3 ? props.camera3 :
vars.activeCamera === 4 ? props.camera4 :
vars.activeCamera === 5 ? props.camera5 :
vars.activeCamera === 6 ? props.camera6 :
vars.activeCamera === 7 ? props.camera7 : props.camera1) +
'_MP4_History_Length'].state > 0"
- component: f7-badge
config:
color: red
style:
border-radius: 50%
height: 20px
left: 50%
position: absolute
top: 5px
transform: translateX(-50%)
width: 12px
z-index: 3
visible: "= items[(vars.activeCamera === 1 || vars.activeCamera === undefined ?
props.camera1 : vars.activeCamera === 2 ? props.camera2 :
vars.activeCamera === 3 ? props.camera3 :
vars.activeCamera === 4 ? props.camera4 :
vars.activeCamera === 5 ? props.camera5 :
vars.activeCamera === 6 ? props.camera6 :
vars.activeCamera === 7 ? props.camera7 : props.camera1) +
'_MP4_Recording'].state !== NULL &&
items[(vars.activeCamera === 1 || vars.activeCamera ===
undefined ? props.camera1 : vars.activeCamera === 2 ?
props.camera2 : vars.activeCamera === 3 ? props.camera3 :
vars.activeCamera === 4 ? props.camera4 :
vars.activeCamera === 5 ? props.camera5 :
vars.activeCamera === 6 ? props.camera6 :
vars.activeCamera === 7 ? props.camera7 : props.camera1) +
'_MP4_Recording'].state > 0 && vars.archive !== 2"
- component: f7-block
config:
style:
background: var(--f7-theme-color)
border-radius: 0px
margin: 0
padding: 8px 15px 15px 15px
position: relative
visible: =vars.archive !== 2 && ((vars.activeCamera === 1 || vars.activeCamera
=== undefined) && (!!props.camera1PtzPresetItem ||
!!props.camera1PtzAutoResetItem) || vars.activeCamera === 2 &&
(!!props.camera2PtzPresetItem || !!props.camera2PtzAutoResetItem) ||
vars.activeCamera === 3 && (!!props.camera3PtzPresetItem ||
!!props.camera3PtzAutoResetItem) || vars.activeCamera === 4 &&
(!!props.camera4PtzPresetItem || !!props.camera4PtzAutoResetItem) ||
vars.activeCamera === 5 && (!!props.camera5PtzPresetItem ||
!!props.camera5PtzAutoResetItem) || vars.activeCamera === 6 &&
(!!props.camera6PtzPresetItem || !!props.camera6PtzAutoResetItem) ||
vars.activeCamera === 7 && (!!props.camera7PtzPresetItem ||
!!props.camera7PtzAutoResetItem))
slots:
default:
- component: f7-row
config:
style:
align-items: center
height: 40px
justify-content: center
margin-bottom: 5px
slots:
default:
- component: oh-button
config:
action: variable
actionVariable: ptzExpanded
actionVariableValue: "=vars.ptzExpanded === 'true' ? 'false' : 'true'"
style:
--f7-button-bg-color: rgba(255,255,255,0.2)
--f7-button-border-radius: 50%
--f7-button-height: 30px
--f7-button-width: 30px
align-items: center
border: 1px solid rgba(255,255,255,0.3)
display: flex
justify-content: center
slots:
default:
- component: f7-icon
config:
f7: "=vars.ptzExpanded === 'true' ? 'chevron_up' : 'chevron_down'"
size: 16
style:
color: white
transition: transform 0.3s ease
- component: f7-block
config:
style:
height: "=vars.ptzExpanded === 'true' ? 'auto' : '0px'"
margin-bottom: 10px
opacity: "=vars.ptzExpanded === 'true' ? '1' : '0'"
overflow: hidden
transition: all 0.3s ease
visible: =(vars.activeCamera === 1 || vars.activeCamera === undefined) &&
!!props.camera1PtzPresetItem || vars.activeCamera === 2 &&
!!props.camera2PtzPresetItem || vars.activeCamera === 3 &&
!!props.camera3PtzPresetItem || vars.activeCamera === 4 &&
!!props.camera4PtzPresetItem || vars.activeCamera === 5 &&
!!props.camera5PtzPresetItem || vars.activeCamera === 6 &&
!!props.camera6PtzPresetItem || vars.activeCamera === 7 &&
!!props.camera7PtzPresetItem
slots:
default:
- component: Label
config:
style:
color: white
font-size: 13px
font-weight: bold
margin-bottom: 6px
text: "Kamera-Position:"
- component: f7-swiper
config:
params:
direction: horizontal
freeMode: true
mousewheel: true
scrollbar:
draggable: true
el: .swiper-scrollbar
slidesPerView: auto
style:
height: 45px
slots:
default:
- component: f7-swiper-slide
config:
style:
padding: 0 4px
width: auto
slots:
default:
- component: oh-button
config:
action: command
actionCommand: "5"
actionItem: "= vars.activeCamera === 1 || vars.activeCamera === undefined ?
props.camera1PtzPresetItem : vars.activeCamera
=== 2 ? props.camera2PtzPresetItem :
vars.activeCamera === 3 ?
props.camera3PtzPresetItem : vars.activeCamera
=== 4 ? props.camera4PtzPresetItem :
vars.activeCamera === 5 ?
props.camera5PtzPresetItem : vars.activeCamera
=== 6 ? props.camera6PtzPresetItem :
vars.activeCamera === 7 ?
props.camera7PtzPresetItem :
props.camera1PtzPresetItem"
style:
align-items: center
background: rgba(255,255,255,0.2)
border: 1px solid rgba(255,255,255,0.3)
border-radius: 6px
color: white
display: flex
font-size: 12px
font-weight: bold
justify-content: center
min-width: 70px
padding: 6px 10px
text-align: center
text: Terrasse
- component: f7-swiper-slide
config:
style:
padding: 0 4px
width: auto
slots:
default:
- component: oh-button
config:
action: command
actionCommand: "1"
actionItem: "= vars.activeCamera === 1 || vars.activeCamera === undefined ?
props.camera1PtzPresetItem : vars.activeCamera
=== 2 ? props.camera2PtzPresetItem :
vars.activeCamera === 3 ?
props.camera3PtzPresetItem : vars.activeCamera
=== 4 ? props.camera4PtzPresetItem :
vars.activeCamera === 5 ?
props.camera5PtzPresetItem : vars.activeCamera
=== 6 ? props.camera6PtzPresetItem :
vars.activeCamera === 7 ?
props.camera7PtzPresetItem :
props.camera1PtzPresetItem"
style:
align-items: center
background: rgba(255,255,255,0.2)
border: 1px solid rgba(255,255,255,0.3)
border-radius: 6px
color: white
display: flex
font-size: 12px
font-weight: bold
justify-content: center
min-width: 70px
padding: 6px 10px
text-align: center
text: Garten
- component: f7-swiper-slide
config:
style:
padding: 0 4px
width: auto
slots:
default:
- component: oh-button
config:
action: command
actionCommand: "4"
actionItem: "= vars.activeCamera === 1 || vars.activeCamera === undefined ?
props.camera1PtzPresetItem : vars.activeCamera
=== 2 ? props.camera2PtzPresetItem :
vars.activeCamera === 3 ?
props.camera3PtzPresetItem : vars.activeCamera
=== 4 ? props.camera4PtzPresetItem :
vars.activeCamera === 5 ?
props.camera5PtzPresetItem : vars.activeCamera
=== 6 ? props.camera6PtzPresetItem :
vars.activeCamera === 7 ?
props.camera7PtzPresetItem :
props.camera1PtzPresetItem"
style:
align-items: center
background: rgba(255,255,255,0.2)
border: 1px solid rgba(255,255,255,0.3)
border-radius: 6px
color: white
display: flex
font-size: 12px
font-weight: bold
justify-content: center
min-width: 70px
padding: 6px 10px
text-align: center
text: Gartentür
- component: f7-swiper-slide
config:
style:
padding: 0 4px
width: auto
slots:
default:
- component: oh-button
config:
action: command
actionCommand: "3"
actionItem: "= vars.activeCamera === 1 || vars.activeCamera === undefined ?
props.camera1PtzPresetItem : vars.activeCamera
=== 2 ? props.camera2PtzPresetItem :
vars.activeCamera === 3 ?
props.camera3PtzPresetItem : vars.activeCamera
=== 4 ? props.camera4PtzPresetItem :
vars.activeCamera === 5 ?
props.camera5PtzPresetItem : vars.activeCamera
=== 6 ? props.camera6PtzPresetItem :
vars.activeCamera === 7 ?
props.camera7PtzPresetItem :
props.camera1PtzPresetItem"
style:
align-items: center
background: rgba(255,255,255,0.2)
border: 1px solid rgba(255,255,255,0.3)
border-radius: 6px
color: white
display: flex
font-size: 12px
font-weight: bold
justify-content: center
min-width: 80px
padding: 6px 10px
text-align: center
text: Mähroboter
- component: f7-swiper-slide
config:
style:
padding: 0 4px
width: auto
slots:
default:
- component: oh-button
config:
action: command
actionCommand: "6"
actionItem: "= vars.activeCamera === 1 || vars.activeCamera === undefined ?
props.camera1PtzPresetItem : vars.activeCamera
=== 2 ? props.camera2PtzPresetItem :
vars.activeCamera === 3 ?
props.camera3PtzPresetItem : vars.activeCamera
=== 4 ? props.camera4PtzPresetItem :
vars.activeCamera === 5 ?
props.camera5PtzPresetItem : vars.activeCamera
=== 6 ? props.camera6PtzPresetItem :
vars.activeCamera === 7 ?
props.camera7PtzPresetItem :
props.camera1PtzPresetItem"
style:
align-items: center
background: rgba(255,255,255,0.2)
border: 1px solid rgba(255,255,255,0.3)
border-radius: 6px
color: white
display: flex
font-size: 12px
font-weight: bold
justify-content: center
min-width: 80px
padding: 6px 10px
text-align: center
text: Ahornbeet
- component: f7-swiper-slide
config:
style:
padding: 0 4px
width: auto
slots:
default:
- component: oh-button
config:
action: command
actionCommand: "2"
actionItem: "= vars.activeCamera === 1 || vars.activeCamera === undefined ?
props.camera1PtzPresetItem : vars.activeCamera
=== 2 ? props.camera2PtzPresetItem :
vars.activeCamera === 3 ?
props.camera3PtzPresetItem : vars.activeCamera
=== 4 ? props.camera4PtzPresetItem :
vars.activeCamera === 5 ?
props.camera5PtzPresetItem : vars.activeCamera
=== 6 ? props.camera6PtzPresetItem :
vars.activeCamera === 7 ?
props.camera7PtzPresetItem :
props.camera1PtzPresetItem"
style:
align-items: center
background: rgba(255,255,255,0.2)
border: 1px solid rgba(255,255,255,0.3)
border-radius: 6px
color: white
display: flex
font-size: 12px
font-weight: bold
justify-content: center
min-width: 70px
padding: 6px 10px
text-align: center
text: Freisitz
- component: f7-swiper-slide
config:
style:
padding: 0 4px
width: auto
slots:
default:
- component: oh-button
config:
action: command
actionCommand: "7"
actionItem: "= vars.activeCamera === 1 || vars.activeCamera === undefined ?
props.camera1PtzPresetItem : vars.activeCamera
=== 2 ? props.camera2PtzPresetItem :
vars.activeCamera === 3 ?
props.camera3PtzPresetItem : vars.activeCamera
=== 4 ? props.camera4PtzPresetItem :
vars.activeCamera === 5 ?
props.camera5PtzPresetItem : vars.activeCamera
=== 6 ? props.camera6PtzPresetItem :
vars.activeCamera === 7 ?
props.camera7PtzPresetItem :
props.camera1PtzPresetItem"
style:
align-items: center
background: rgba(255,255,255,0.2)
border: 1px solid rgba(255,255,255,0.3)
border-radius: 6px
color: white
display: flex
font-size: 12px
font-weight: bold
justify-content: center
min-width: 70px
padding: 6px 10px
text-align: center
text: O. Rasen
- component: f7-swiper-slide
config:
style:
padding: 0 4px
width: auto
slots:
default:
- component: oh-button
config:
action: command
actionCommand: "8"
actionItem: "= vars.activeCamera === 1 || vars.activeCamera === undefined ?
props.camera1PtzPresetItem : vars.activeCamera
=== 2 ? props.camera2PtzPresetItem :
vars.activeCamera === 3 ?
props.camera3PtzPresetItem : vars.activeCamera
=== 4 ? props.camera4PtzPresetItem :
vars.activeCamera === 5 ?
props.camera5PtzPresetItem : vars.activeCamera
=== 6 ? props.camera6PtzPresetItem :
vars.activeCamera === 7 ?
props.camera7PtzPresetItem :
props.camera1PtzPresetItem"
style:
align-items: center
background: rgba(255,255,255,0.2)
border: 1px solid rgba(255,255,255,0.3)
border-radius: 6px
color: white
display: flex
font-size: 12px
font-weight: bold
justify-content: center
min-width: 70px
padding: 6px 10px
text-align: center
text: Balkon
- component: f7-swiper-slide
config:
style:
padding: 0 4px
width: auto
slots:
default:
- component: oh-button
config:
action: command
actionCommand: "9"
actionItem: "= vars.activeCamera === 1 || vars.activeCamera === undefined ?
props.camera1PtzPresetItem : vars.activeCamera
=== 2 ? props.camera2PtzPresetItem :
vars.activeCamera === 3 ?
props.camera3PtzPresetItem : vars.activeCamera
=== 4 ? props.camera4PtzPresetItem :
vars.activeCamera === 5 ?
props.camera5PtzPresetItem : vars.activeCamera
=== 6 ? props.camera6PtzPresetItem :
vars.activeCamera === 7 ?
props.camera7PtzPresetItem :
props.camera1PtzPresetItem"
style:
align-items: center
background: rgba(255,255,255,0.2)
border: 1px solid rgba(255,255,255,0.3)
border-radius: 6px
color: white
display: flex
font-size: 12px
font-weight: bold
justify-content: center
min-width: 110px
padding: 6px 10px
text-align: center
text: Haus und Dach
- component: f7-block
config:
style:
height: "=vars.ptzExpanded === 'true' ? 'auto' : '0px'"
opacity: "=vars.ptzExpanded === 'true' ? '1' : '0'"
overflow: hidden
transition: all 0.3s ease
visible: =(vars.activeCamera === 1 || vars.activeCamera === undefined) &&
!!props.camera1PtzAutoResetItem || vars.activeCamera === 2 &&
!!props.camera2PtzAutoResetItem || vars.activeCamera === 3 &&
!!props.camera3PtzAutoResetItem || vars.activeCamera === 4 &&
!!props.camera4PtzAutoResetItem || vars.activeCamera === 5 &&
!!props.camera5PtzAutoResetItem || vars.activeCamera === 6 &&
!!props.camera6PtzAutoResetItem || vars.activeCamera === 7 &&
!!props.camera7PtzAutoResetItem
slots:
default:
- component: Label
config:
style:
color: white
font-size: 13px
font-weight: bold
margin-bottom: 6px
text: "PTZ-Modus:"
- component: f7-row
config:
style:
gap: 6px
slots:
default:
- component: oh-button
config:
action: command
actionCommand: "1"
actionItem: "= vars.activeCamera === 1 || vars.activeCamera === undefined ?
props.camera1PtzAutoResetItem : vars.activeCamera
=== 2 ? props.camera2PtzAutoResetItem :
vars.activeCamera === 3 ?
props.camera3PtzAutoResetItem : vars.activeCamera
=== 4 ? props.camera4PtzAutoResetItem :
vars.activeCamera === 5 ?
props.camera5PtzAutoResetItem : vars.activeCamera
=== 6 ? props.camera6PtzAutoResetItem :
vars.activeCamera === 7 ?
props.camera7PtzAutoResetItem :
props.camera1PtzAutoResetItem"
style:
align-items: center
background: rgba(255,255,255,0.2)
border: 1px solid rgba(255,255,255,0.3)
border-radius: 6px
color: white
display: flex
flex: 1
font-size: 12px
font-weight: bold
justify-content: center
padding: 8px
text-align: center
text: Auto-Reset
- component: oh-button
config:
action: command
actionCommand: "2"
actionItem: "= vars.activeCamera === 1 || vars.activeCamera === undefined ?
props.camera1PtzAutoResetItem : vars.activeCamera
=== 2 ? props.camera2PtzAutoResetItem :
vars.activeCamera === 3 ?
props.camera3PtzAutoResetItem : vars.activeCamera
=== 4 ? props.camera4PtzAutoResetItem :
vars.activeCamera === 5 ?
props.camera5PtzAutoResetItem : vars.activeCamera
=== 6 ? props.camera6PtzAutoResetItem :
vars.activeCamera === 7 ?
props.camera7PtzAutoResetItem :
props.camera1PtzAutoResetItem"
style:
align-items: center
background: rgba(255,255,255,0.2)
border: 1px solid rgba(255,255,255,0.3)
border-radius: 6px
color: white
display: flex
flex: 1
font-size: 12px
font-weight: bold
justify-content: center
padding: 8px
text-align: center
text: Kamerafahrt
- component: oh-button
config:
action: command
actionCommand: "3"
actionItem: "= vars.activeCamera === 1 || vars.activeCamera === undefined ?
props.camera1PtzAutoResetItem : vars.activeCamera
=== 2 ? props.camera2PtzAutoResetItem :
vars.activeCamera === 3 ?
props.camera3PtzAutoResetItem : vars.activeCamera
=== 4 ? props.camera4PtzAutoResetItem :
vars.activeCamera === 5 ?
props.camera5PtzAutoResetItem : vars.activeCamera
=== 6 ? props.camera6PtzAutoResetItem :
vars.activeCamera === 7 ?
props.camera7PtzAutoResetItem :
props.camera1PtzAutoResetItem"
style:
align-items: center
background: rgba(255,255,255,0.2)
border: 1px solid rgba(255,255,255,0.3)
border-radius: 6px
color: white
display: flex
flex: 1
font-size: 12px
font-weight: bold
justify-content: center
padding: 8px
text-align: center
text: Manuell
- component: f7-block
config:
style:
background: var(--f7-theme-color)
border-radius: 0px
margin: 0
padding: 8px 15px
visible: =vars.archive === 2 || !((vars.activeCamera === 1 || vars.activeCamera
=== undefined) && (!!props.camera1PtzPresetItem ||
!!props.camera1PtzAutoResetItem) || vars.activeCamera === 2 &&
(!!props.camera2PtzPresetItem || !!props.camera2PtzAutoResetItem) ||
vars.activeCamera === 3 && (!!props.camera3PtzPresetItem ||
!!props.camera3PtzAutoResetItem) || vars.activeCamera === 4 &&
(!!props.camera4PtzPresetItem || !!props.camera4PtzAutoResetItem) ||
vars.activeCamera === 5 && (!!props.camera5PtzPresetItem ||
!!props.camera5PtzAutoResetItem) || vars.activeCamera === 6 &&
(!!props.camera6PtzPresetItem || !!props.camera6PtzAutoResetItem) ||
vars.activeCamera === 7 && (!!props.camera7PtzPresetItem ||
!!props.camera7PtzAutoResetItem))
slots:
default:
- component: Label
config:
style:
display: block
height: 1px
text: ""
- component: f7-popup
config:
backdrop: true
closeByBackdropClick: true
closeByOutsideClick: true
closeOnEscape: true
id: fullscreenCamera
opened: =vars.fullscreenOpen === 'true'
style:
background: black
z-index: 10000
slots:
default:
- component: f7-block
config:
style:
align-items: center
background: black
display: flex
height: 100vh
justify-content: center
margin: 0
padding: 0
position: relative
width: 100vw
slots:
default:
- component: oh-image-card
config:
item: "= vars.activeCamera === 1 || vars.activeCamera === undefined ?
props.camera1ImageItem : vars.activeCamera === 2 ?
props.camera2ImageItem : vars.activeCamera === 3 ?
props.camera3ImageItem : vars.activeCamera === 4 ?
props.camera4ImageItem : vars.activeCamera === 5 ?
props.camera5ImageItem : vars.activeCamera === 6 ?
props.camera6ImageItem : vars.activeCamera === 7 ?
props.camera7ImageItem : props.camera1ImageItem"
noBorder: true
noShadow: true
refreshInterval: =props.refreshRate
style:
background: transparent
height: 100%
object-fit: contain
width: 100%
- component: oh-button
config:
action: variable
actionVariable: fullscreenOpen
actionVariableValue: "false"
iconColor: red
iconF7: xmark
iconSize: 28
style:
height: 32px
margin: -2px
position: absolute
right: 0px
top: 0px
width: 32px
z-index: 10001