refactored camera full screen support
authorCalin Crisan <ccrisan@gmail.com>
Thu, 3 Dec 2015 20:15:33 +0000 (22:15 +0200)
committerCalin Crisan <ccrisan@gmail.com>
Thu, 3 Dec 2015 20:15:33 +0000 (22:15 +0200)
motioneye/static/css/frame.css
motioneye/static/css/main.css
motioneye/static/js/frame.js
motioneye/static/js/main.js
motioneye/templates/main.html

index ff0b35f3aff4b8c96bf590d6013b3f901e236169..e0bac9fcf5ef9c06bf998440772fd0d86bc010bd 100644 (file)
@@ -14,6 +14,7 @@ div.camera-frame {
     position: relative;
     padding: 0px;
     margin: 0px;
+    border: 0px;
     width: 100%;
     height: 100%;
 }
index 23ec58dc96e76ba78de6ad32a2f32bfc244e72c5..4e4c65796d0e217039bd203f4708875942c4f3a6 100644 (file)
@@ -71,7 +71,7 @@ div.header-container {
 
 div.page {
     font-size: 1em;
-    transition: all 0.5s linear;
+    transition: all 0.5s ease;
     min-height: 100%;
 }
 
@@ -84,10 +84,15 @@ div.header {
     position: fixed;
     overflow: hidden;
     z-index: 10000;
+    transition: all 0.2s ease;
+}
+
+div.header.full-screen {
+    height: 0px;
 }
 
 div.header-container {
-    transition: all 0.5s linear;
+    transition: all 0.5s ease;
 }
 
 div.footer {
@@ -98,6 +103,12 @@ div.footer {
     font-size: 0.7em;
     color: #aaa;
     text-align: center;
+    transition: all 0.2s ease;
+    overflow: hidden;
+}
+
+div.footer.full-screen {
+    height: 0px;
 }
 
 div.copyright-note {
@@ -107,7 +118,7 @@ div.copyright-note {
 }
 
 div.page-container {
-    transition: all 0.1s linear;
+    transition: all 0.2s ease;
     padding: 50px 0.2em 50px 0px;
 }
 
@@ -128,6 +139,11 @@ div.page-container.four-columns.stretched {
     font-size: 10px;
 }
 
+div.page-container.full-screen {
+    padding-top: 0px;
+    padding-bottom: 0px;
+}
+
 
     /* icons & icon buttons */
 
@@ -244,7 +260,7 @@ div.settings {
     left: 0px;
     width: 0px;
     bottom: 0px;
-    transition: all 0.2s linear;
+    transition: all 0.2s ease;
     overflow: auto;
 }
 
@@ -837,13 +853,14 @@ div.camera-frame {
     border: 0.2em solid #212121;
     border-right-width: 0px;
     border-bottom-width: 0px;
-    transition: all 0.1s linear, opacity 0s;
+    transition: all 0.1s ease, opacity 0s;
     opacity: 0;
     vertical-align: top;
     cursor: pointer;
     -webkit-user-select: none;
     -moz-user-select: none;
     user-select: none;
+    overflow: hidden;
 }
 
 div.camera-frame:HOVER {
@@ -863,18 +880,25 @@ div.page-container.two-columns div.camera-frame {
 }
 
 div.page-container.three-columns div.camera-frame {
-    width: 33%;
+    width: 33.3333%;
 }
 
 div.page-container.four-columns div.camera-frame {
     width: 25%;
 }
 
-div.modal-container div.camera-frame {
-    width: auto;
+div.page-container div.camera-frame.full-screen-hidden {
+    width: 0px !important;
+    height: 0px !important;
     padding: 0px;
-    margin: -7px;
-    background-color: #414141;
+    border: 0px;
+    margin: 0px;
+}
+
+div.page-container div.camera-frame.full-screen {
+    width: 100%;
+    height: auto;
+    transition: all 0.4s ease; /* prevents unwanted camera frame line wrapping */
 }
 
 div.camera-overlay {
@@ -884,7 +908,7 @@ div.camera-overlay {
     left: 0.2em;
     bottom: 0.2em;
     opacity: 0;
-    transition: all 0.2s linear;
+    transition: all 0.2s ease;
 }
 
 div.camera-overlay.visible {
@@ -895,7 +919,7 @@ div.camera-overlay-top,
 div.camera-overlay-bottom {
     position: absolute;
     background-color: rgba(0, 0, 0, 0.7);
-    transition: background-color 0.1s linear;
+    transition: background-color 0.1s ease;
     left: 0px;
     width: 100%;
 }
@@ -1061,7 +1085,7 @@ img.camera {
     position: relative;
     width: 100%;
     display: block;
-    transition: opacity 0.2s linear;
+    transition: opacity 0.2s ease;
     opacity: 1;
     min-height: 160px;
 }
@@ -1078,7 +1102,7 @@ div.camera-placeholder {
     bottom: 0px;
     left: 0px;
     text-align: center;
-    transition: opacity 0.2s linear;
+    transition: opacity 0.2s ease;
 }
 
 img.no-camera {
@@ -1095,7 +1119,7 @@ div.camera-progress {
     bottom: 0px;
     left: 0px;
     opacity: 0;
-    transition: all 0.2s linear;
+    transition: all 0.2s ease;
     text-align: center;
     cursor: pointer;
 }
index c61475cdb10522cd826fbfb8b633a3021730add5..03afd011d0ecdecaecd8f308e5357ae01310fc9d 100644 (file)
@@ -15,7 +15,7 @@ function setupCameraFrame() {
     
     cameraFrameDiv[0].refreshDivider = 0;
     cameraFrameDiv[0].streamingFramerate = parseInt(cameraFrameDiv.attr('streaming_framerate')) || 1;
-    cameraFrameDiv[0].streamingServerResize = cameraFrameDiv.attr('streaming_server_resize') == 'True';
+    cameraFrameDiv[0].streamingServerResize = cameraFrameDiv.attr('streaming_server_resize') == 'true';
     cameraFrameDiv[0].proto = cameraFrameDiv.attr('proto');
     cameraFrameDiv[0].url = cameraFrameDiv.attr('url');
     progressImg.attr('src', staticPath + 'img/camera-progress.gif');
index 13c0a3a31eb8e80ff1700cc5dad260d9efca8ee4..c6c1924716446b881e4b06e50b9f0770c54bec5c 100644 (file)
@@ -2656,6 +2656,12 @@ function getCameraIdsByInstance() {
     return cameraIdsByInstance;
 }
 
+function getCameraIds() {
+    return getCameraFrames().map(function () {
+        return this.config.id;
+    }).toArray();
+}
+
 
     /* dialogs */
 
@@ -3693,10 +3699,10 @@ function addCameraFrameUi(cameraConfig) {
                     '<div class="camera-overlay-top">' +
                         '<div class="camera-name"><span class="camera-name"></span></div>' +
                         '<div class="camera-top-buttons">' +
-                            '<div class="button icon camera-top-button mouse-effect full-screen" title="full-screen window"></div>' +
-                            '<div class="button icon camera-top-button mouse-effect media-pictures" title="pictures"></div>' +
-                            '<div class="button icon camera-top-button mouse-effect media-movies" title="movies"></div>' +
-                            '<div class="button icon camera-top-button mouse-effect configure" title="configure"></div>' +
+                            '<div class="button icon camera-top-button mouse-effect full-screen" title="toggle full-screen camera"></div>' +
+                            '<div class="button icon camera-top-button mouse-effect media-pictures" title="open pictures browser"></div>' +
+                            '<div class="button icon camera-top-button mouse-effect media-movies" title="open movies browser"></div>' +
+                            '<div class="button icon camera-top-button mouse-effect configure" title="configure this camera"></div>' +
                         '</div>' +
                     '</div>' +
                     '<div class="camera-overlay-bottom">' +
@@ -3712,7 +3718,7 @@ function addCameraFrameUi(cameraConfig) {
                                 '<div class="button icon camera-action-button mouse-effect unlock" title="unlock"></div>' +
                                 '<div class="button icon camera-action-button mouse-effect light-off" title="turn light off"></div>' +
                                 '<div class="button icon camera-action-button mouse-effect alarm-off" title="turn alarm off"></div>' +
-                                '<div class="button icon camera-action-button mouse-effect record-start" title="record"></div>' +
+                                '<div class="button icon camera-action-button mouse-effect record-start" title="toggle continuous recording mode"></div>' +
                             '</div>' +
                         '</div>' +
                     '</div>' +
@@ -3818,8 +3824,12 @@ function addCameraFrameUi(cameraConfig) {
     
     fullScreenButton.click(function (cameraId) {
         return function () {
-            var path = basePath + 'picture/' + cameraId + '/frame/';
-            window.open(path, '_blank');
+            if (fullScreenCameraId && fullScreenCameraId == cameraId) {
+                doExitFullScreenCamera();
+            }
+            else {
+                doFullScreenCamera(cameraId);
+            }
         };
     }(cameraId));
     
@@ -4018,7 +4028,7 @@ function doConfigureCamera(cameraId) {
 }
 
 function doFullScreenCamera(cameraId) {
-    if (inProgress || refreshDisabled[cameraId]) {
+    if (inProgress) {
         return;
     }
     
@@ -4026,64 +4036,62 @@ function doFullScreenCamera(cameraId) {
         return; /* a camera is already in full screen */
     }
     
-    fullScreenCameraId = -1; /* avoids successive fast toggles of fullscreen */
+    closeSettings();
     
-    var cameraFrameDiv = getCameraFrame(cameraId);
-    var cameraName = cameraFrameDiv.find('span.camera-name').text();
-    var cameraImg = cameraFrameDiv.find('img.camera');
-    var aspectRatio = cameraImg.width() / cameraImg.height();
-    var windowWidth = $(window).width();
-    var windowHeight = $(window).height();
-    var windowAspectRatio = windowWidth / windowHeight;
-    var frameIndex = cameraFrameDiv.index();
+    fullScreenCameraId = cameraId;
     
-    cameraImg.addClass('initializing');
-    cameraImg[0].initializing = true;
+    var cameraIds = getCameraIds();
+    cameraIds.forEach(function (cid) {
+        if (cid == cameraId) {
+            return;
+        }
+        
+        refreshDisabled[cid] |= 0;
+        refreshDisabled[cid]++;
+        
+        var cf = getCameraFrame(cid);
+        cf.css('height', cf.height()); /* required for the height animation */
+        setTimeout(function () {
+            cf.addClass('full-screen-hidden');
+        }, 10);
+    });
     
-    if (cameraImg.hasClass('error')) {
-        return; /* no full screen for erroneous cameras */
-    }
+    var cameraFrame = getCameraFrame(cameraId);
+    var pageContainer = getPageContainer();
+    
+    pageContainer.addClass('full-screen');
+    cameraFrame.addClass('full-screen');
+    $('div.header').addClass('full-screen')
+    $('div.footer').addClass('full-screen')
+}
 
-    var width;
-    if (windowAspectRatio > aspectRatio) {
-        width = aspectRatio * Math.round(0.8 * windowHeight);
-    }
-    else {
-        width = Math.round(0.9 * windowWidth);
+function doExitFullScreenCamera() {
+    if (fullScreenCameraId == null) {
+        return; /* no current full-screen camera */
     }
-
-    cameraFrameDiv.find('div.camera-progress').addClass('visible');
+        
+    getCameraFrames().
+            removeClass('full-screen-hidden').
+            css('height', '');
     
-    var cameraImg = cameraFrameDiv.find('img.camera');
-    cameraImg.load(function showFullScreenCamera() {
-        cameraFrameDiv.css('width', width);
-        fullScreenCameraId = cameraId;
+    var cameraFrame = getCameraFrame(fullScreenCameraId);
+    var pageContainer = getPageContainer();
+    
+    $('div.header').removeClass('full-screen')
+    $('div.footer').removeClass('full-screen')
+    pageContainer.removeClass('full-screen');
+    cameraFrame.removeClass('full-screen');
+
+    var cameraIds = getCameraIds();
+    cameraIds.forEach(function (cid) {
+        if (cid == fullScreenCameraId) {
+            return;
+        }
         
-        runModalDialog({
-            title: cameraName,
-            closeButton: true,
-            content: cameraFrameDiv,
-            onShow: function () {
-                cameraImg.unbind('load', showFullScreenCamera);
-            },
-            onClose: function () {
-                fullScreenCameraId = null;
-                cameraFrameDiv.css('width', '');
-                var nextFrame = getPageContainer().children('div:eq(' + frameIndex + ')');
-                if (nextFrame.length) {
-                    nextFrame.before(cameraFrameDiv);
-                }
-                else {
-                    getPageContainer().append(cameraFrameDiv);
-                }
-            }
-        });
+        refreshDisabled[cid]--;
     });
-    
-    if (cameraFrameDiv[0].config['proto'] == 'mjpeg') {
-        /* manually trigger the load event on simple mjpeg cameras */
-        cameraImg.load();
-    }
+
+    fullScreenCameraId = null;
 }
 
 function refreshCameraFrames() {
@@ -4247,5 +4255,6 @@ $(document).ready(function () {
     
     refreshCameraFrames();
     checkCameraErrors();
+    setLayoutColumns(3); // TODO !!!
 });
 
index 66e8acc7294ed22f51355af5fd4b28fa1aab4d4d..a28d830c83dc67937db982bb3aa9deb2490562fc 100644 (file)
     </div>
     {% else %}
         <div class="camera-frame" id="camera{{camera_id}}"
-                streaming_framerate="{{camera_config['stream_maxrate']}}" streaming_server_resize="{{camera_config['@webcam_server_resize']}}"
+                streaming_framerate="{{camera_config['stream_maxrate']}}" streaming_server_resize="{{camera_config['@webcam_server_resize']|string|lower}}"
                 proto="{{camera_config['@proto']}}" url="{{camera_config['@url']}}">
             
             <div class="camera-container">