diff options
author | Devaev Maxim <[email protected]> | 2018-10-07 18:24:20 +0300 |
---|---|---|
committer | Devaev Maxim <[email protected]> | 2018-10-07 18:35:28 +0300 |
commit | 447b949273d5a6ba52388b7f7540cfedc0b74f54 (patch) | |
tree | 32af2eb5355f805265103b13458350ddc40c752b | |
parent | 053755fdc0cef8d43147d22d457f2882bdad117f (diff) |
web: auto-resize stream
-rw-r--r-- | web/css/mobile.css | 3 | ||||
-rw-r--r-- | web/css/stream.css | 7 | ||||
-rw-r--r-- | web/css/switches.css | 76 | ||||
-rw-r--r-- | web/index.html | 20 | ||||
-rw-r--r-- | web/js/stream.js | 106 | ||||
-rw-r--r-- | web/js/ui.js | 28 |
6 files changed, 180 insertions, 60 deletions
diff --git a/web/css/mobile.css b/web/css/mobile.css index fdec7fc3..04e548e7 100644 --- a/web/css/mobile.css +++ b/web/css/mobile.css @@ -83,5 +83,8 @@ div#stream-size-slider-box input[type=range] { margin: 20px 0 20px 0 !important; } + table#stream-auto-resize-box { + margin: 20px 0 20px 0 !important; + } } } diff --git a/web/css/stream.css b/web/css/stream.css index 0ddcf780..2e7aa32c 100644 --- a/web/css/stream.css +++ b/web/css/stream.css @@ -39,8 +39,6 @@ select#stream-quality-select { margin: 8px 0 8px 0; } -span#stream-size-value { -} div#stream-size-slider-box { margin-top: 5px; display: flex; @@ -93,6 +91,11 @@ div#stream-size-slider-box input[type=range]::-moz-range-thumb { background: var(--bg-color-intensive); } +table#stream-auto-resize-box { + width: 100%; + border-collapse: collapse; +} + div#stream-mouse-buttons { display: none; margin: 0; diff --git a/web/css/switches.css b/web/css/switches.css new file mode 100644 index 00000000..3a97b072 --- /dev/null +++ b/web/css/switches.css @@ -0,0 +1,76 @@ +div.switch-box { + display: inline-block; + vertical-align: middle; + position: relative; + width: 50px; + -webkit-user-select: none; + -moz-user-select: none; +} + +div.switch-box input[type=checkbox].switch-checkbox { + display: none; +} + +div.switch-box label.switch-label { + display: block; + overflow: hidden; + cursor: pointer; + border: none; + border-radius: 15px; +} + +div.switch-box span.switch-inner { + display: block; + width: 200%; + margin-left: -100%; +} + +div.switch-box span.switch-inner:before, span.switch-inner:after { + display: block; + float: left; + width: 50%; + height: 20px; + padding: 0; + line-height: 22px; + font-size: 10px; + font-family: sans-serif !important; + font-weight: bold; + box-sizing: border-box; +} + +div.switch-box span.switch-inner:before { + content: "ON"; + padding-left: 5px; + background-color: var(--bg-color-gray); + color: var(--fg-color-normal); + text-align: left; +} + +div.switch-box span.switch-inner:after { + content: "OFF"; + padding-right: 5px; + background-color: var(--bg-color-gray); + color: var(--fg-color-inactive); + text-align: right; +} + +div.switch-box span.switch { + display: block; + width: 15px; + margin: 0px; + background: var(--bg-color-intensive); + position: absolute; + top: 0; + bottom: 0; + right: 31px; + border: var(--intensive-border); + border-radius: 15px; +} + +div.switch-box input[type=checkbox].switch-checkbox:checked + label.switch-label span.switch-inner { + margin-left: 0; +} + +div.switch-box input[type=checkbox].switch-checkbox:checked + label.switch-label span.switch { + right: 0px; +} diff --git a/web/index.html b/web/index.html index 71e068d1..0f3c1d0a 100644 --- a/web/index.html +++ b/web/index.html @@ -14,6 +14,7 @@ <link rel="stylesheet" href="css/windows.css"> <link rel="stylesheet" href="css/modals.css"> <link rel="stylesheet" href="css/leds.css"> + <link rel="stylesheet" href="css/switches.css"> <link rel="stylesheet" href="css/stream.css"> <link rel="stylesheet" href="css/hid.css"> <link rel="stylesheet" href="css/msd.css"> @@ -76,17 +77,32 @@ </div> <hr> <div data-dont-hide-menu class="ctl-dropdown-content-text"> - Quality: + Stream quality: <select disabled id="stream-quality-select"></select> </div> <hr> <div data-dont-hide-menu class="ctl-dropdown-content-text"> Stream size: <span id="stream-size-value">100%</span> <div id="stream-size-slider-box"> - <input id="stream-size-slider" type="range" min="50" max="150" value="100" step="10" /> + <input id="stream-size-slider" type="range" /> </div> </div> <hr> + <div data-dont-hide-menu class="ctl-dropdown-content-text"> + <table id="stream-auto-resize-box"><tr> + <td>Auto-resize stream:</td> + <td align="right"> + <div class="switch-box"> + <input type="checkbox" class="switch-checkbox" id="stream-auto-resize-checkbox" checked /> + <label class="switch-label" for="stream-auto-resize-checkbox"> + <span class="switch-inner"></span> + <span class="switch"></span> + </label> + </div> + </td> + </tr></table> + </div> + <hr> <div class="ctl-dropdown-content-buttons"> <button disabled id="stream-reset-button">• Reset stream</button> <button disabled id="hid-reset-button">• Reset keyboard & mouse</button> diff --git a/web/js/stream.js b/web/js/stream.js index 9de67dcc..91f2dc92 100644 --- a/web/js/stream.js +++ b/web/js/stream.js @@ -4,7 +4,7 @@ function Stream() { /********************************************************************************/ var __prev_state = false; - var __normal_size = {width: 640, height: 480}; + var __resolution = {width: 640, height: 480}; var __client_id = ""; var __fps = 0; @@ -23,8 +23,13 @@ function Stream() { tools.setOnClick($("stream-screenshot-button"), __clickScreenshotButton); $("stream-quality-select").onchange = __changeQuality; - $("stream-size-slider").oninput = __resize; - $("stream-size-slider").onchange = __resize; + + $("stream-size-slider").min = 50; + $("stream-size-slider").max = 150; + $("stream-size-slider").step = 10; + $("stream-size-slider").value = 100; + $("stream-size-slider").oninput = () => __resize; + $("stream-size-slider").onchange = () => __resize; tools.setOnClick($("stream-reset-button"), __clickResetButton); @@ -42,8 +47,6 @@ function Stream() { if (http.status !== 200) { tools.info("Refreshing stream ..."); - __prev_state = false; - __fps = 0; $("stream-image").className = "stream-image-inactive"; $("stream-box").classList.add("stream-box-inactive"); $("stream-led").className = "led-off"; @@ -52,24 +55,22 @@ function Stream() { $("stream-quality-select").disabled = true; $("stream-reset-button").disabled = true; __updateStreamHeader(false); + __fps = 0; + __prev_state = false; } else if (http.status === 200) { - if (__prev_state) { - if (__normal_size != response.stream.resolution) { - __normal_size = response.stream.resolution; + if (__quality != response.source.quality) { + document.querySelector("#stream-quality-select [value=\"" + response.source.quality + "\"]").selected = true; + __quality = response.source.quality; + } + + if (__resolution.width !== response.source.resolution.width || __resolution.height !== response.source.resolution.height) { + __resolution = response.source.resolution; + if ($("stream-auto-resize-checkbox").checked) { + __adjustSizeFactor(); + } else { __applySizeFactor(); } - } else { - __normal_size = response.stream.resolution; - __refreshImage(); - __prev_state = true; - $("stream-image").className = "stream-image-active"; - $("stream-box").classList.remove("stream-box-inactive"); - $("stream-led").className = "led-on"; - $("stream-led").title = "Stream is active"; - $("stream-screenshot-button").disabled = false; - $("stream-quality-select").disabled = false; - $("stream-reset-button").disabled = false; } var client_id = tools.getCookie("stream_client_id"); @@ -84,6 +85,19 @@ function Stream() { } __updateStreamHeader(true); + + if (!__prev_state) { + tools.info("Stream acquired"); + $("stream-image").src = "/streamer/stream?t=" + new Date().getTime(); + $("stream-image").className = "stream-image-active"; + $("stream-box").classList.remove("stream-box-inactive"); + $("stream-led").className = "led-on"; + $("stream-led").title = "Stream is active"; + $("stream-screenshot-button").disabled = false; + $("stream-quality-select").disabled = false; + $("stream-reset-button").disabled = false; + __prev_state = true; + } } } }); @@ -93,7 +107,7 @@ function Stream() { var __updateStreamHeader = function(online) { var el_grab = document.querySelector("#stream-window-header .window-grab"); if (online) { - el_grab.innerHTML = "Stream – " + __normal_size.width + "x" + __normal_size.height + " / " + __fps + " fps"; + el_grab.innerHTML = "Stream – " + __resolution.width + "x" + __resolution.height + " / " + __fps + " fps"; } else { el_grab.innerHTML = "Stream – offline"; } @@ -133,35 +147,43 @@ function Stream() { } }; - var __resize = function() { + var __resize = function(center=false) { var percent = $("stream-size-slider").value; $("stream-size-value").innerHTML = percent + "%"; __size_factor = percent / 100; - __applySizeFactor(); - }; - - var __applySizeFactor = function() { - var el_stream_image = $("stream-image"); - el_stream_image.style.width = __normal_size.width * __size_factor + "px"; - el_stream_image.style.height = __normal_size.height * __size_factor + "px"; - ui.showWindow($("stream-window"), false); + __applySizeFactor(center); }; - var __refreshImage = function() { - var http = tools.makeRequest("GET", "/kvmd/streamer", function() { - if (http.readyState === 4 && http.status === 200) { - var result = JSON.parse(http.responseText).result; + var __adjustSizeFactor = function() { + var el_window = $("stream-window"); + var el_slider = $("stream-size-slider"); + var view = ui.getViewGeometry(); + + for (var percent = 100; percent >= el_slider.min; percent -= el_slider.step) { + tools.info("Adjusting size:", percent); + $("stream-size-slider").value = percent; + __resize(true); + + var rect = el_window.getBoundingClientRect(); + if ( + rect.bottom <= view.bottom + && rect.top >= view.top + && rect.left >= view.left + && rect.right <= view.right + ) { + return; + } + } - if (__quality != result.quality) { - tools.info("Quality changed:", result.quality); - document.querySelector("#stream-quality-select [value=\"" + result.quality + "\"]").selected = true; - __quality = result.quality; - } + $("stream-size-slider").value = 100; + __resize(); + }; - __applySizeFactor(); - $("stream-image").src = "/streamer/stream?t=" + new Date().getTime(); - } - }); + var __applySizeFactor = function(center=false) { + var el_stream_image = $("stream-image"); + el_stream_image.style.width = __resolution.width * __size_factor + "px"; + el_stream_image.style.height = __resolution.height * __size_factor + "px"; + ui.showWindow($("stream-window"), false, center); }; __init__(); diff --git a/web/js/ui.js b/web/js/ui.js index d04184c1..20bba472 100644 --- a/web/js/ui.js +++ b/web/js/ui.js @@ -122,9 +122,9 @@ function Ui() { return promise; }; - self.showWindow = function(el_window, raise=true) { - if (!__isWindowOnPage(el_window) || el_window.hasAttribute("data-centered")) { - var view = __getViewGeometry(); + self.showWindow = function(el_window, raise=true, center=false) { + if (!__isWindowOnPage(el_window) || el_window.hasAttribute("data-centered") || center) { + var view = self.getViewGeometry(); var rect = el_window.getBoundingClientRect(); el_window.style.top = Math.max($("ctl").clientHeight, Math.round((view.bottom - rect.height) / 2)) + "px"; el_window.style.left = Math.round((view.right - rect.width) / 2) + "px"; @@ -136,8 +136,17 @@ function Ui() { } }; + self.getViewGeometry = function() { + return { + top: $("ctl").clientHeight, + bottom: Math.max(document.documentElement.clientHeight, window.innerHeight || 0), + left: 0, + right: Math.max(document.documentElement.clientWidth, window.innerWidth || 0), + }; + }; + var __isWindowOnPage = function(el_window) { - var view = __getViewGeometry(); + var view = self.getViewGeometry(); var rect = el_window.getBoundingClientRect(); return ( @@ -148,15 +157,6 @@ function Ui() { ); }; - var __getViewGeometry = function() { - return { - top: $("ctl").clientHeight, - bottom: Math.max(document.documentElement.clientHeight, window.innerHeight || 0), - left: 0, - right: Math.max(document.documentElement.clientWidth, window.innerWidth || 0), - }; - }; - var __toggleMenu = function(el_a) { var all_hidden = true; @@ -211,7 +211,7 @@ function Ui() { }; var __organizeWindowsOnResize = function(orientation) { - var view = __getViewGeometry(); + var view = self.getViewGeometry(); Array.prototype.forEach.call($$("window"), function(el_window) { if (el_window.style.visibility === "visible" && (orientation || el_window.hasAttribute("data-centered"))) { var rect = el_window.getBoundingClientRect(); |