Placeholder for webcam image to avoid moving controls on load
An aspect ratio of 16:9 is assumed, with other ratios showing black letterbox borders as required. During loading a text "Webcam loading..." is displayed in the webcam space. On loading error, the (broken) image is hidden and an error text is displayed instead. Solves #478
This commit is contained in:
parent
f32d7c434d
commit
c844217f82
4 changed files with 130 additions and 30 deletions
File diff suppressed because one or more lines are too long
|
|
@ -37,6 +37,8 @@ $(function() {
|
|||
self.additionalControls = [];
|
||||
|
||||
self.webcamDisableTimeout = undefined;
|
||||
self.webcamLoaded = ko.observable(false);
|
||||
self.webcamError = ko.observable(false);
|
||||
|
||||
self.keycontrolActive = ko.observable(false);
|
||||
self.keycontrolHelpActive = ko.observable(false);
|
||||
|
|
@ -343,42 +345,24 @@ $(function() {
|
|||
self.requestData();
|
||||
};
|
||||
|
||||
self.updateRotatorWidth = function() {
|
||||
var webcamImage = $("#webcam_image");
|
||||
if (self.settings.webcam_rotate90()) {
|
||||
if (webcamImage.width() > 0) {
|
||||
$("#webcam_rotator").css("height", webcamImage.width());
|
||||
} else {
|
||||
webcamImage.off("load.rotator");
|
||||
webcamImage.on("load.rotator", function() {
|
||||
$("#webcam_rotator").css("height", webcamImage.width());
|
||||
webcamImage.off("load.rotator");
|
||||
});
|
||||
}
|
||||
} else {
|
||||
$("#webcam_rotator").css("height", "");
|
||||
}
|
||||
};
|
||||
|
||||
self.onSettingsBeforeSave = self.updateRotatorWidth;
|
||||
|
||||
self._isSafari = function() {
|
||||
var is_chrome = navigator.userAgent.indexOf('Chrome') > -1;
|
||||
var is_safari = navigator.userAgent.indexOf("Safari") > -1;
|
||||
return is_safari && !is_chrome;
|
||||
}
|
||||
};
|
||||
|
||||
self._disableWebcam = function() {
|
||||
// only disable webcam stream if tab is out of focus for more than 5s, otherwise we might cause
|
||||
// more load by the constant connection creation than by the actual webcam stream
|
||||
|
||||
|
||||
// safari bug doesn't release the mjpeg stream, so we just disable this for safari.
|
||||
if (self._isSafari()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
self.webcamDisableTimeout = setTimeout(function () {
|
||||
$("#webcam_image").attr("src", "");
|
||||
self.webcamLoaded(false);
|
||||
}, 5000);
|
||||
};
|
||||
|
||||
|
|
@ -392,12 +376,12 @@ $(function() {
|
|||
}
|
||||
var webcamImage = $("#webcam_image");
|
||||
var currentSrc = webcamImage.attr("src");
|
||||
|
||||
|
||||
// safari bug doesn't release the mjpeg stream, so we just set it up the once
|
||||
if (self._isSafari() && currentSrc != undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var newSrc = self.settings.webcam_streamUrl();
|
||||
if (currentSrc != newSrc) {
|
||||
if (newSrc.lastIndexOf("?") > -1) {
|
||||
|
|
@ -407,11 +391,24 @@ $(function() {
|
|||
}
|
||||
newSrc += new Date().getTime();
|
||||
|
||||
self.updateRotatorWidth();
|
||||
self.webcamLoaded(false);
|
||||
self.webcamError(false);
|
||||
webcamImage.attr("src", newSrc);
|
||||
}
|
||||
};
|
||||
|
||||
self.onWebcamLoaded = function() {
|
||||
log.debug("Webcam stream loaded");
|
||||
self.webcamLoaded(true);
|
||||
self.webcamError(false);
|
||||
};
|
||||
|
||||
self.onWebcamErrored = function() {
|
||||
log.debug("Webcam stream failed to load/disabled");
|
||||
self.webcamLoaded(false);
|
||||
self.webcamError(true);
|
||||
};
|
||||
|
||||
self.onTabChange = function (current, previous) {
|
||||
if (current == "#control") {
|
||||
self._enableWebcam();
|
||||
|
|
|
|||
|
|
@ -491,7 +491,7 @@ ul.dropdown-menu li a {
|
|||
position: relative;
|
||||
outline: none;
|
||||
|
||||
//min-height: 440px;
|
||||
background-color: black;
|
||||
|
||||
.keycontrol_overlay {
|
||||
position: absolute;
|
||||
|
|
@ -526,6 +526,84 @@ ul.dropdown-menu li a {
|
|||
float: left;
|
||||
}
|
||||
}
|
||||
|
||||
.nowebcam {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
|
||||
.text {
|
||||
color: white;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
margin: auto;
|
||||
width: 80%;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
display: block;
|
||||
|
||||
&.webcam_loading {
|
||||
animation: pulsate 3s ease-out;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.webcam_rotated {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding-bottom: 100%;
|
||||
|
||||
.webcam_fixed_ratio {
|
||||
position: absolute;
|
||||
transform: rotate(-90deg);
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
|
||||
.webcam_fixed_ratio_inner {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.webcam_unrotated {
|
||||
.webcam_fixed_ratio {
|
||||
width: 100%;
|
||||
padding-bottom: 100%;
|
||||
|
||||
&.ratio43 {
|
||||
padding-bottom: 75%;
|
||||
}
|
||||
|
||||
&.ratio169 {
|
||||
padding-bottom: 56.25%;
|
||||
}
|
||||
|
||||
&.ratio1610 {
|
||||
padding-bottom: 62.5%;
|
||||
}
|
||||
|
||||
position: relative;
|
||||
|
||||
.webcam_fixed_ratio_inner {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
/** State sidebar panel */
|
||||
|
|
@ -757,7 +835,7 @@ ul.dropdown-menu li a {
|
|||
#terminal-sendpanel {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
|
||||
#terminal-output span {
|
||||
display: block;
|
||||
}
|
||||
|
|
@ -871,6 +949,18 @@ textarea.block {
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
@keyframes pulsate {
|
||||
0% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
50% {
|
||||
opacity: 1.0;
|
||||
}
|
||||
100% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
#drop_overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,20 @@
|
|||
{% if webcamStream %}
|
||||
<div id="webcam_container" tabindex="0" data-bind="event: { keydown: onKeyDown, mouseover: onMouseOver, mouseout: onMouseOut, focus: onFocus }">
|
||||
<div id="webcam_rotator" data-bind="css: { rotate90: settings.webcam_rotate90() }">
|
||||
<img id="webcam_image" data-bind="css: { flipH: settings.webcam_flipH(), flipV: settings.webcam_flipV() }">
|
||||
<div class="nowebcam" data-bind="visible: !webcamLoaded()">
|
||||
<div class="text webcam_loading" data-bind="visible: !webcamLoaded() && !webcamError()">
|
||||
<p><strong>{{ _('Webcam stream loading...') }}</strong></p>
|
||||
</div>
|
||||
<div class="text webcam_error" data-bind="visible: !webcamLoaded() && webcamError()">
|
||||
<p><strong>{{ _('Webcam stream not loaded') }}</strong></p>
|
||||
<p><small>{{ _('It might not be correctly configured. You can change the URL of the stream under "Settings" > "Webcam & Timelapse" > "Stream URL". If you don\'t have a webcam just set the URL to an empty value.') }}</small></p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="webcam_rotator" data-bind="css: { webcam_rotated: settings.webcam_rotate90(), webcam_unrotated: !settings.webcam_rotate90() }">
|
||||
<div class="webcam_fixed_ratio ratio169">
|
||||
<div class="webcam_fixed_ratio_inner">
|
||||
<img id="webcam_image" data-bind="css: { flipH: settings.webcam_flipH(), flipV: settings.webcam_flipV() }, event: { load: onWebcamLoaded, error: onWebcamErrored }, visible: !webcamError()">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="keycontrol_overlay" data-bind="visible: showKeycontrols">
|
||||
<div class="keycontrol_overlay_heading">{{ _("Keyboard controls active") }} <a href="#" data-bind="click: toggleKeycontrolHelp"><i data-bind="css: { 'icon-chevron-down': !keycontrolHelpActive(), 'icon-chevron-up': keycontrolHelpActive() }"></i></a></div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue