From eab6c09d3e810da50c737f28d95956b6ac28724c Mon Sep 17 00:00:00 2001 From: Evan Theurer Date: Fri, 23 May 2014 16:35:55 +0200 Subject: [PATCH 1/7] Update 'take a profile picture' implementation to allow preview of taken picture. --- src/styles/components/_settings.scss | 18 ++++ static/js/directives/settings.js | 122 +++++++++++++++++---------- static/partials/settings.html | 18 +++- 3 files changed, 112 insertions(+), 46 deletions(-) diff --git a/src/styles/components/_settings.scss b/src/styles/components/_settings.scss index 85d0a7a5..9322706b 100644 --- a/src/styles/components/_settings.scss +++ b/src/styles/components/_settings.scss @@ -71,6 +71,24 @@ right: 10px; top: 10px; } + .showTakePicture { + position: relative; + .btn { + margin: 5px 0px; + } + } + .btn-takePicture { + position: absolute; + top: 110px; + right: 90px; + } + .countdownToTakePicture { + font-size: 45px; + color: $componentbg; + position: absolute; + top: 55px; + left: 95px; + } .form-horizontal { .controls { @include breakpt($breakpoint-settings-medium, max-width, only screen) { diff --git a/static/js/directives/settings.js b/static/js/directives/settings.js index 3b51c132..5853ac6b 100644 --- a/static/js/directives/settings.js +++ b/static/js/directives/settings.js @@ -22,11 +22,12 @@ define(['underscore', 'text!partials/settings.html'], function(_, template) { return ["$compile", "mediaStream", function($compile, mediaStream) { - var controller = ['$scope', 'desktopNotify', 'mediaSources', 'safeApply', 'availableLanguages', 'translation', function($scope, desktopNotify, mediaSources, safeApply, availableLanguages, translation) { + var controller = ['$scope', 'desktopNotify', 'mediaSources', 'safeApply', 'availableLanguages', 'translation', '$timeout',function($scope, desktopNotify, mediaSources, safeApply, availableLanguages, translation, $timeout) { $scope.layout.settings = false; $scope.showAdvancedSettings = true; $scope.showTakePicture = false; + $scope.previewPicture = false; $scope.showTakePictureReady = true; $scope.rememberSettings = true; $scope.desktopNotify = desktopNotify; @@ -72,59 +73,92 @@ define(['underscore', 'text!partials/settings.html'], function(_, template) { safeApply($scope); }); }; - $scope.takePicture = function(element, stop) { + $scope.takePicture = function(element, take, retake, stop) { + var delayToTakePicture = 3000; + var takePictureCountFrom = 3; + var takePictureCountDown = function() { + $scope.countdown = {}; + $scope.countdown.num = 3; + $timeout(function() { + $scope.countdown.num = 2; + }, delayToTakePicture/takePictureCountFrom*1); + $timeout(function() { + $scope.countdown.num = 1; + }, delayToTakePicture/takePictureCountFrom*2); + $timeout(function() { + $scope.countdown.num = null; + }, delayToTakePicture/takePictureCountFrom*3); + }; + if (stop) { $scope.showTakePicture = false; + $scope.previewPicture = false; if (localStream) { localStream.stop(); localStream = null; } - } else { - var video = $(element).parent().find("video").get(0); - if (!$scope.showTakePicture) { - $scope.showTakePictureReady = false; - var videoConstraints = true; - if ($scope.user.settings.cameraId) { - videoConstraints = { - optional: [{sourceId: $scope.user.settings.cameraId}] - } - } - getUserMedia({video: videoConstraints}, function(stream) { - if ($scope.showTakePictureReady) { - stream.stop() - return; - } - $scope.showTakePicture = true; - localStream = stream; - $scope.showTakePictureReady = true; - attachMediaStream(video, stream); - safeApply($scope); - }, function(error) { - console.error('Failed to get access to local media. Error code was ' + error.code); - $scope.showTakePictureReady = true; - safeApply($scope); - }); - return; - } else { - var canvas = $(element).parent().find("canvas").get(0); - var videoWidth = video.videoWidth; - var videoHeight = video.videoHeight; - var aspectRatio = videoWidth/videoHeight; - if (!aspectRatio) { - // NOTE(longsleep): In Firefox the video size becomes available at sound point later - crap! - console.warn("Unable to compute aspectRatio", aspectRatio); - aspectRatio = 1.3333333333333333; + return; + } + + var video = $(element).parent().parent().find("video").get(0); + var makePicture = function() { + takePictureCountDown(); + $timeout(function() { + $scope.previewPicture = true; + video.pause(); + }, delayToTakePicture); + }; + + if (!$scope.showTakePicture) { + $scope.showTakePictureReady = false; + var videoConstraints = true; + if ($scope.user.settings.cameraId) { + videoConstraints = { + optional: [{sourceId: $scope.user.settings.cameraId}] + }; + } + getUserMedia({video: videoConstraints}, function(stream) { + if ($scope.showTakePictureReady) { + stream.stop(); + return; } - var x = (46*aspectRatio-46)/-2 - canvas.getContext("2d").drawImage(video, x, 0, 46*aspectRatio, 46); - $scope.user.buddyPicture = canvas.toDataURL("image/jpeg"); - console.info("Image size", $scope.user.buddyPicture.length); - localStream.stop(); - localStream = null; + $scope.showTakePicture = true; + localStream = stream; + $scope.showTakePictureReady = true; + attachMediaStream(video, stream); + safeApply($scope); + }, function(error) { + console.error('Failed to get access to local media. Error code was ' + error.code); $scope.showTakePictureReady = true; - $scope.showTakePicture = false; safeApply($scope); + }); + return; + } else if (take) { + makePicture(); + } else if (retake) { + video.play(); + $scope.previewPicture = false; + makePicture(); + } else { + var canvas = $(element).parent().parent().find("canvas").get(0); + var videoWidth = video.videoWidth; + var videoHeight = video.videoHeight; + var aspectRatio = videoWidth/videoHeight; + if (!aspectRatio) { + // NOTE(longsleep): In Firefox the video size becomes available at sound point later - crap! + console.warn("Unable to compute aspectRatio", aspectRatio); + aspectRatio = 1.3333333333333333; } + var x = (46*aspectRatio-46)/-2; + canvas.getContext("2d").drawImage(video, x, 0, 46*aspectRatio, 46); + $scope.user.buddyPicture = canvas.toDataURL("image/jpeg"); + console.info("Image size", $scope.user.buddyPicture.length); + localStream.stop(); + localStream = null; + $scope.showTakePictureReady = true; + $scope.showTakePicture = false; + $scope.previewPicture = false; + safeApply($scope); } }; diff --git a/static/partials/settings.html b/static/partials/settings.html index d525d49b..c6af57d1 100644 --- a/static/partials/settings.html +++ b/static/partials/settings.html @@ -11,11 +11,25 @@
-
+ +
+ {{_('Take picture')}} + + {{_('Waiting for camera')}} +
- {{_('Take picture')}} {{_('Waiting for camera')}} {{_('Cancel')}}
From 61f8574548b38335a2af0a7e180e492329d169df Mon Sep 17 00:00:00 2001 From: Evan Theurer Date: Mon, 26 May 2014 12:43:36 +0200 Subject: [PATCH 2/7] Fix build error from semicolon. --- build/build.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.js b/build/build.js index 4597e157..4ba0524a 100644 --- a/build/build.js +++ b/build/build.js @@ -60,4 +60,4 @@ inlineText: true, } ] -}); +}) From 1fc810a9d5fce8066c9c0e25d35224343371c5ad Mon Sep 17 00:00:00 2001 From: Evan Theurer Date: Mon, 26 May 2014 14:13:48 +0200 Subject: [PATCH 3/7] Refactor countdown. --- static/js/directives/settings.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/static/js/directives/settings.js b/static/js/directives/settings.js index cdf69312..d3b217ec 100644 --- a/static/js/directives/settings.js +++ b/static/js/directives/settings.js @@ -80,19 +80,19 @@ define(['jquery', 'underscore', 'text!partials/settings.html'], function($, _, t }; $scope.takePicture = function(element, take, retake, stop) { var delayToTakePicture = 3000; - var takePictureCountFrom = 3; - var takePictureCountDown = function() { + var countDownFrom = 3; + // Counts down from start to 1 + var takePictureCountDown = function(start, delayTotal) { $scope.countdown = {}; - $scope.countdown.num = 3; - $timeout(function() { - $scope.countdown.num = 2; - }, delayToTakePicture/takePictureCountFrom*1); - $timeout(function() { - $scope.countdown.num = 1; - }, delayToTakePicture/takePictureCountFrom*2); - $timeout(function() { - $scope.countdown.num = null; - }, delayToTakePicture/takePictureCountFrom*3); + $scope.countdown.num = start; + var decrementNum = function(num) { + $timeout(function() { + $scope.countdown.num--; + }, delayTotal/start*num); + } + for(var i = 1; i <= start; i++) { + decrementNum(i); + } }; if (stop) { @@ -107,7 +107,7 @@ define(['jquery', 'underscore', 'text!partials/settings.html'], function($, _, t var video = $(element).parent().parent().find("video").get(0); var makePicture = function() { - takePictureCountDown(); + takePictureCountDown(countDownFrom, delayToTakePicture); $timeout(function() { $scope.previewPicture = true; video.pause(); From 7305d0a9eaca8f40f1d467defb8b788418179d92 Mon Sep 17 00:00:00 2001 From: Evan Theurer Date: Tue, 27 May 2014 11:58:18 +0200 Subject: [PATCH 4/7] Breakout picture functionality into own directive. Update functions. Create corresponding styles page. --- src/styles/components/_buddypicture.scss | 45 +++++++ src/styles/components/_settings.scss | 18 --- src/styles/main.scss | 1 + static/js/directives/buddypicture.js | 151 +++++++++++++++++++++++ static/js/directives/directives.js | 4 +- static/js/directives/settings.js | 99 +-------------- static/partials/buddypicture.html | 20 +++ static/partials/settings.html | 25 +--- 8 files changed, 223 insertions(+), 140 deletions(-) create mode 100644 src/styles/components/_buddypicture.scss create mode 100644 static/js/directives/buddypicture.js create mode 100644 static/partials/buddypicture.html diff --git a/src/styles/components/_buddypicture.scss b/src/styles/components/_buddypicture.scss new file mode 100644 index 00000000..049db70d --- /dev/null +++ b/src/styles/components/_buddypicture.scss @@ -0,0 +1,45 @@ +/* + * Spreed WebRTC. + * Copyright (C) 2013-2014 struktur AG + * + * This file is part of Spreed WebRTC. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +.buddyPicture { + .picture { + display: block; + margin-bottom: 5px; + } + .showTakePicture { + position: relative; + .btn { + margin: 5px 0px; + } + } + .btn-takePicture { + position: absolute; + right: 90px; + top: 110px; + } + .countdownPicture { + color: $componentbg; + font-size: 45px; + left: 95px; + position: absolute; + top: 55px; + } +} diff --git a/src/styles/components/_settings.scss b/src/styles/components/_settings.scss index 9392e133..171fed4f 100644 --- a/src/styles/components/_settings.scss +++ b/src/styles/components/_settings.scss @@ -71,24 +71,6 @@ right: 10px; top: 10px; } - .showTakePicture { - position: relative; - .btn { - margin: 5px 0px; - } - } - .btn-takePicture { - position: absolute; - top: 110px; - right: 90px; - } - .countdownToTakePicture { - font-size: 45px; - color: $componentbg; - position: absolute; - top: 55px; - left: 95px; - } .form-horizontal { .controls { @include breakpt($breakpoint-settings-medium, max-width, only screen) { diff --git a/src/styles/main.scss b/src/styles/main.scss index 4d9c69bf..90b959ad 100644 --- a/src/styles/main.scss +++ b/src/styles/main.scss @@ -35,6 +35,7 @@ @import "components/rightslide"; @import "components/bar"; @import "components/buddylist"; +@import "components/buddypicture"; @import "components/settings"; @import "components/chat"; @import "components/usability"; diff --git a/static/js/directives/buddypicture.js b/static/js/directives/buddypicture.js new file mode 100644 index 00000000..46a77228 --- /dev/null +++ b/static/js/directives/buddypicture.js @@ -0,0 +1,151 @@ +/* + * Spreed WebRTC. + * Copyright (C) 2013-2014 struktur AG + * + * This file is part of Spreed WebRTC. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +define(['jquery', 'underscore', 'text!partials/buddypicture.html'], function($, _, template) { + + return ["$compile", function($compile) { + + var controller = ['$scope', 'safeApply', '$timeout', function($scope, safeApply, $timeout) { + + $scope.showTakePicture = false; + $scope.showTakePictureReady = true; + $scope.previewPicture = false; + $scope.countingDown = false; + $scope.video = null; + $scope.canvas = null; + + var localStream = null; + var delayToTakePicture = 3000; + var countDownFrom = 3; + + // Counts down from start to 1 + var takePictureCountDown = function(start, delayTotal) { + $scope.countingDown = true; + $scope.countdown = {}; + $scope.countdown.num = start; + var decrementNum = function(num) { + $timeout(function() { + $scope.countdown.num--; + if($scope.countdown.num === 0) { + $scope.countingDown = false; + } + }, delayTotal/start*num); + }; + for(var i = 1; i <= start; i++) { + decrementNum(i); + } + }; + + var makePicture = function(cntFrom, delayTotal) { + takePictureCountDown(cntFrom, delayTotal); + $timeout(function() { + $scope.previewPicture = true; + $scope.video.pause(); + }, delayTotal); + }; + + $scope.initPicture = function() { + $scope.showTakePictureReady = false; + var videoConstraints = true; + if ($scope.user.settings.cameraId) { + videoConstraints = { + optional: [{ + sourceId: $scope.user.settings.cameraId + }] + }; + } + getUserMedia({ + video: videoConstraints + }, function(stream) { + if ($scope.showTakePictureReady) { + stream.stop(); + return; + } + $scope.showTakePicture = true; + localStream = stream; + $scope.showTakePictureReady = true; + attachMediaStream($scope.video, stream); + safeApply($scope); + }, function(error) { + console.error('Failed to get access to local media. Error code was ' + error.code); + $scope.showTakePictureReady = true; + safeApply($scope); + }); + }; + + $scope.cancelPicture = function() { + $scope.showTakePicture = false; + $scope.previewPicture = false; + if (localStream) { + localStream.stop(); + localStream = null; + } + }; + + $scope.retakePicture = function() { + $scope.video.play(); + $scope.previewPicture = false; + makePicture(countDownFrom, delayToTakePicture); + }; + + $scope.takePicture = function() { + makePicture(countDownFrom, delayToTakePicture); + }; + + $scope.setAsProfilePicture = function() { + var videoWidth = $scope.video.videoWidth; + var videoHeight = $scope.video.videoHeight; + var aspectRatio = videoWidth/videoHeight; + if (!aspectRatio) { + // NOTE(longsleep): In Firefox the video size becomes available at sound point later - crap! + console.warn("Unable to compute aspectRatio", aspectRatio); + aspectRatio = 1.3333333333333333; + } + var x = (46 * aspectRatio - 46) / -2; + $scope.canvas.getContext("2d").drawImage($scope.video, x, 0, 46 * aspectRatio, 46); + $scope.user.buddyPicture = $scope.canvas.toDataURL("image/jpeg"); + console.info("Image size", $scope.user.buddyPicture.length); + localStream.stop(); + localStream = null; + $scope.showTakePictureReady = true; + $scope.showTakePicture = false; + $scope.previewPicture = false; + safeApply($scope); + }; + + }]; + + var link = function($scope, $element) { + $scope.video = $element.find("video").get(0); + $scope.canvas = $element.find("canvas").get(0); + }; + + return { + scope: true, + restrict: 'E', + replace: true, + template: template, + controller: controller, + link: link + }; + + }]; + +}); diff --git a/static/js/directives/directives.js b/static/js/directives/directives.js index 66bfbe79..510fd6e3 100644 --- a/static/js/directives/directives.js +++ b/static/js/directives/directives.js @@ -25,6 +25,7 @@ define([ 'directives/onescape', 'directives/statusmessage', 'directives/buddylist', + 'directives/buddypicture', 'directives/settings', 'directives/chat', 'directives/audiovideo', @@ -34,13 +35,14 @@ define([ 'directives/screenshare', 'directives/roombar', 'directives/socialshare', - 'directives/page'], function(_, onEnter, onEscape, statusMessage, buddyList, settings, chat, audioVideo, usability, audioLevel, fileInfo, screenshare, roomBar, socialShare, page) { + 'directives/page'], function(_, onEnter, onEscape, statusMessage, buddyList, buddyPicture, settings, chat, audioVideo, usability, audioLevel, fileInfo, screenshare, roomBar, socialShare, page) { var directives = { onEnter: onEnter, onEscape: onEscape, statusMessage: statusMessage, buddyList: buddyList, + buddyPicture: buddyPicture, settings: settings, chat: chat, audioVideo: audioVideo, diff --git a/static/js/directives/settings.js b/static/js/directives/settings.js index d3b217ec..6716aa05 100644 --- a/static/js/directives/settings.js +++ b/static/js/directives/settings.js @@ -22,13 +22,10 @@ define(['jquery', 'underscore', 'text!partials/settings.html'], function($, _, t return ["$compile", "mediaStream", function($compile, mediaStream) { - var controller = ['$scope', 'desktopNotify', 'mediaSources', 'safeApply', 'availableLanguages', 'translation', '$timeout', function($scope, desktopNotify, mediaSources, safeApply, availableLanguages, translation, $timeout) { + var controller = ['$scope', 'desktopNotify', 'mediaSources', 'safeApply', 'availableLanguages', 'translation', function($scope, desktopNotify, mediaSources, safeApply, availableLanguages, translation) { $scope.layout.settings = false; $scope.showAdvancedSettings = true; - $scope.showTakePicture = false; - $scope.showTakePictureReady = true; - $scope.previewPicture = false; $scope.rememberSettings = true; $scope.desktopNotify = desktopNotify; $scope.mediaSources = mediaSources; @@ -47,8 +44,6 @@ define(['jquery', 'underscore', 'text!partials/settings.html'], function($, _, t }); }); - var localStream = null; - // Make sure to save settings when they are open and the page is reloaded. $(window).on("unload", function() { if ($scope.layout.settings) { @@ -78,98 +73,6 @@ define(['jquery', 'underscore', 'text!partials/settings.html'], function($, _, t safeApply($scope); }); }; - $scope.takePicture = function(element, take, retake, stop) { - var delayToTakePicture = 3000; - var countDownFrom = 3; - // Counts down from start to 1 - var takePictureCountDown = function(start, delayTotal) { - $scope.countdown = {}; - $scope.countdown.num = start; - var decrementNum = function(num) { - $timeout(function() { - $scope.countdown.num--; - }, delayTotal/start*num); - } - for(var i = 1; i <= start; i++) { - decrementNum(i); - } - }; - - if (stop) { - $scope.showTakePicture = false; - $scope.previewPicture = false; - if (localStream) { - localStream.stop(); - localStream = null; - } - return; - } - - var video = $(element).parent().parent().find("video").get(0); - var makePicture = function() { - takePictureCountDown(countDownFrom, delayToTakePicture); - $timeout(function() { - $scope.previewPicture = true; - video.pause(); - }, delayToTakePicture); - }; - - if (!$scope.showTakePicture) { - $scope.showTakePictureReady = false; - var videoConstraints = true; - if ($scope.user.settings.cameraId) { - videoConstraints = { - optional: [{ - sourceId: $scope.user.settings.cameraId - }] - }; - } - getUserMedia({ - video: videoConstraints - }, function(stream) { - if ($scope.showTakePictureReady) { - stream.stop(); - return; - } - $scope.showTakePicture = true; - localStream = stream; - $scope.showTakePictureReady = true; - attachMediaStream(video, stream); - safeApply($scope); - }, function(error) { - console.error('Failed to get access to local media. Error code was ' + error.code); - $scope.showTakePictureReady = true; - safeApply($scope); - }); - return; - } else if (take) { - makePicture(); - } else if (retake) { - video.play(); - $scope.previewPicture = false; - makePicture(); - } else { - var canvas = $(element).parent().parent().find("canvas").get(0); - var videoWidth = video.videoWidth; - var videoHeight = video.videoHeight; - var aspectRatio = videoWidth/videoHeight; - if (!aspectRatio) { - // NOTE(longsleep): In Firefox the video size becomes available at sound point later - crap! - console.warn("Unable to compute aspectRatio", aspectRatio); - aspectRatio = 1.3333333333333333; - } - var x = (46 * aspectRatio - 46) / -2; - canvas.getContext("2d").drawImage(video, x, 0, 46 * aspectRatio, 46); - $scope.user.buddyPicture = canvas.toDataURL("image/jpeg"); - console.info("Image size", $scope.user.buddyPicture.length); - localStream.stop(); - localStream = null; - $scope.showTakePictureReady = true; - $scope.showTakePicture = false; - $scope.previewPicture = false; - safeApply($scope); - } - }; $scope.registerUserid = function(btn) { diff --git a/static/partials/buddypicture.html b/static/partials/buddypicture.html new file mode 100644 index 00000000..59c7d081 --- /dev/null +++ b/static/partials/buddypicture.html @@ -0,0 +1,20 @@ + diff --git a/static/partials/settings.html b/static/partials/settings.html index 198fbbda..8a53772d 100644 --- a/static/partials/settings.html +++ b/static/partials/settings.html @@ -5,31 +5,10 @@ {{_('Settings')}}
- +
From 04ab1ae7e22c24ce6ffc2f343ef97362ae566271 Mon Sep 17 00:00:00 2001 From: Evan Theurer Date: Tue, 27 May 2014 13:52:31 +0200 Subject: [PATCH 5/7] Fix take picture button issue with other languages. --- src/styles/components/_buddypicture.scss | 11 +++++--- static/partials/buddypicture.html | 34 +++++++++++------------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/styles/components/_buddypicture.scss b/src/styles/components/_buddypicture.scss index 049db70d..29259796 100644 --- a/src/styles/components/_buddypicture.scss +++ b/src/styles/components/_buddypicture.scss @@ -24,21 +24,24 @@ display: block; margin-bottom: 5px; } - .showTakePicture { + .videoPicture { position: relative; + } + .showTakePicture { .btn { margin: 5px 0px; } } - .btn-takePicture { + .btn-takePicture, + .btn-retakePicture { position: absolute; - right: 90px; + left: 85px; top: 110px; } .countdownPicture { color: $componentbg; font-size: 45px; - left: 95px; + left: 90px; position: absolute; top: 55px; } diff --git a/static/partials/buddypicture.html b/static/partials/buddypicture.html index 59c7d081..f514d730 100644 --- a/static/partials/buddypicture.html +++ b/static/partials/buddypicture.html @@ -1,20 +1,18 @@ From b907999f81e7b21458a97644087fc8ac792ab1bf Mon Sep 17 00:00:00 2001 From: Evan Theurer Date: Fri, 30 May 2014 12:11:44 +0200 Subject: [PATCH 6/7] Start/stop video stream when taking/retaking a picture. --- src/styles/components/_buddypicture.scss | 11 ++++ static/js/directives/buddypicture.js | 75 ++++++++++++++---------- static/partials/buddypicture.html | 13 ++-- 3 files changed, 62 insertions(+), 37 deletions(-) diff --git a/src/styles/components/_buddypicture.scss b/src/styles/components/_buddypicture.scss index 29259796..cab9a654 100644 --- a/src/styles/components/_buddypicture.scss +++ b/src/styles/components/_buddypicture.scss @@ -27,6 +27,17 @@ .videoPicture { position: relative; } + video#prim { + //nothing + } + video#sec { + position: absolute; + top: 0; + left: 0; + &.previewPicture { + position: relative; + } + } .showTakePicture { .btn { margin: 5px 0px; diff --git a/static/js/directives/buddypicture.js b/static/js/directives/buddypicture.js index 46a77228..c631e779 100644 --- a/static/js/directives/buddypicture.js +++ b/static/js/directives/buddypicture.js @@ -22,13 +22,14 @@ define(['jquery', 'underscore', 'text!partials/buddypicture.html'], function($, return ["$compile", function($compile) { - var controller = ['$scope', 'safeApply', '$timeout', function($scope, safeApply, $timeout) { + var controller = ['$scope', 'safeApply', '$timeout', '$q', function($scope, safeApply, $timeout, $q) { $scope.showTakePicture = false; - $scope.showTakePictureReady = true; + $scope.waitingForPermission = false; $scope.previewPicture = false; $scope.countingDown = false; - $scope.video = null; + $scope.videoPrim = null; + $scope.videoSec = null; $scope.canvas = null; var localStream = null; @@ -53,17 +54,28 @@ define(['jquery', 'underscore', 'text!partials/buddypicture.html'], function($, } }; - var makePicture = function(cntFrom, delayTotal) { + var makePicture = function(stream, cntFrom, delayTotal) { takePictureCountDown(cntFrom, delayTotal); + reattachMediaStream($scope.videoSec, $scope.videoPrim); $timeout(function() { $scope.previewPicture = true; - $scope.video.pause(); + videoStop(stream, $scope.videoPrim, $scope.videoSec); }, delayTotal); }; - $scope.initPicture = function() { - $scope.showTakePictureReady = false; + var videoStop = function(stream, video1, video2) { + if (stream) { + video1.pause(); + video2.pause(); + stream.stop(); + stream = null; + } + }; + + var videoStart = function() { + $scope.waitingForPermission = true; var videoConstraints = true; + var videoAllowed = $q.defer(); if ($scope.user.settings.cameraId) { videoConstraints = { optional: [{ @@ -74,44 +86,48 @@ define(['jquery', 'underscore', 'text!partials/buddypicture.html'], function($, getUserMedia({ video: videoConstraints }, function(stream) { - if ($scope.showTakePictureReady) { - stream.stop(); - return; - } $scope.showTakePicture = true; localStream = stream; - $scope.showTakePictureReady = true; - attachMediaStream($scope.video, stream); + $scope.waitingForPermission = false; + attachMediaStream($scope.videoPrim, stream); safeApply($scope); + videoAllowed.resolve(true); }, function(error) { console.error('Failed to get access to local media. Error code was ' + error.code); - $scope.showTakePictureReady = true; + $scope.waitingForPermission = false; safeApply($scope); + videoAllowed.resolve(false); }); + return videoAllowed.promise; + }; + + $scope.initPicture = function() { + videoStart(localStream); }; $scope.cancelPicture = function() { $scope.showTakePicture = false; $scope.previewPicture = false; - if (localStream) { - localStream.stop(); - localStream = null; - } + videoStop(localStream, $scope.videoPrim, $scope.videoSec); }; $scope.retakePicture = function() { - $scope.video.play(); - $scope.previewPicture = false; - makePicture(countDownFrom, delayToTakePicture); + var permission = videoStart(localStream); + permission.then(function(isPermitted) { + if(isPermitted) { + $scope.previewPicture = false; + makePicture(localStream, countDownFrom, delayToTakePicture); + } + }); }; $scope.takePicture = function() { - makePicture(countDownFrom, delayToTakePicture); + makePicture(localStream, countDownFrom, delayToTakePicture); }; $scope.setAsProfilePicture = function() { - var videoWidth = $scope.video.videoWidth; - var videoHeight = $scope.video.videoHeight; + var videoWidth = $scope.videoSec.videoWidth; + var videoHeight = $scope.videoSec.videoHeight; var aspectRatio = videoWidth/videoHeight; if (!aspectRatio) { // NOTE(longsleep): In Firefox the video size becomes available at sound point later - crap! @@ -119,21 +135,18 @@ define(['jquery', 'underscore', 'text!partials/buddypicture.html'], function($, aspectRatio = 1.3333333333333333; } var x = (46 * aspectRatio - 46) / -2; - $scope.canvas.getContext("2d").drawImage($scope.video, x, 0, 46 * aspectRatio, 46); + $scope.canvas.getContext("2d").drawImage($scope.videoSec, x, 0, 46 * aspectRatio, 46); $scope.user.buddyPicture = $scope.canvas.toDataURL("image/jpeg"); console.info("Image size", $scope.user.buddyPicture.length); - localStream.stop(); - localStream = null; - $scope.showTakePictureReady = true; - $scope.showTakePicture = false; - $scope.previewPicture = false; + $scope.cancelPicture(); safeApply($scope); }; }]; var link = function($scope, $element) { - $scope.video = $element.find("video").get(0); + $scope.videoPrim = $element.find("video#prim").get(0); + $scope.videoSec = $element.find("video#sec").get(0); $scope.canvas = $element.find("canvas").get(0); }; diff --git a/static/partials/buddypicture.html b/static/partials/buddypicture.html index f514d730..40982eef 100644 --- a/static/partials/buddypicture.html +++ b/static/partials/buddypicture.html @@ -3,16 +3,17 @@ - {{_('Take picture')}} - + {{_('Take picture')}} + {{_('Waiting for camera')}} From 80121696ea62e90cf77febe5cde7b7bf70f9baf2 Mon Sep 17 00:00:00 2001 From: Evan Theurer Date: Fri, 30 May 2014 14:36:15 +0200 Subject: [PATCH 7/7] Move to displaying preview image in video element to img element using canvas. --- src/styles/components/_buddypicture.scss | 9 ++-- static/js/directives/buddypicture.js | 56 ++++++++++++++---------- static/partials/buddypicture.html | 7 +-- 3 files changed, 39 insertions(+), 33 deletions(-) diff --git a/src/styles/components/_buddypicture.scss b/src/styles/components/_buddypicture.scss index cab9a654..af2322ab 100644 --- a/src/styles/components/_buddypicture.scss +++ b/src/styles/components/_buddypicture.scss @@ -27,13 +27,10 @@ .videoPicture { position: relative; } - video#prim { - //nothing - } - video#sec { + .preview { + left: 0; position: absolute; top: 0; - left: 0; &.previewPicture { position: relative; } @@ -45,8 +42,8 @@ } .btn-takePicture, .btn-retakePicture { - position: absolute; left: 85px; + position: absolute; top: 110px; } .countdownPicture { diff --git a/static/js/directives/buddypicture.js b/static/js/directives/buddypicture.js index c631e779..4e88a1c8 100644 --- a/static/js/directives/buddypicture.js +++ b/static/js/directives/buddypicture.js @@ -28,9 +28,9 @@ define(['jquery', 'underscore', 'text!partials/buddypicture.html'], function($, $scope.waitingForPermission = false; $scope.previewPicture = false; $scope.countingDown = false; - $scope.videoPrim = null; - $scope.videoSec = null; - $scope.canvas = null; + $scope.video = null; + $scope.canvasPic = null; + $scope.canvasPrev = null; var localStream = null; var delayToTakePicture = 3000; @@ -54,19 +54,35 @@ define(['jquery', 'underscore', 'text!partials/buddypicture.html'], function($, } }; + var getCanvasAspectRatio = function() { + var videoWidth = $scope.video.videoWidth; + var videoHeight = $scope.video.videoHeight; + var aspectRatio = videoWidth/videoHeight; + if (!aspectRatio) { + // NOTE(longsleep): In Firefox the video size becomes available at sound point later - crap! + console.warn("Unable to compute aspectRatio", aspectRatio); + aspectRatio = 1.3333333333333333; + } + return aspectRatio; + }; + + var writePreviewPic = function() { + $scope.canvasPrev.getContext("2d").drawImage($scope.video, 0, 0, $scope.video.width, $scope.video.width/getCanvasAspectRatio()); + $scope.preview = $scope.canvasPrev.toDataURL("image/jpeg"); + }; + var makePicture = function(stream, cntFrom, delayTotal) { takePictureCountDown(cntFrom, delayTotal); - reattachMediaStream($scope.videoSec, $scope.videoPrim); $timeout(function() { + videoStop(stream, $scope.video); + writePreviewPic(); $scope.previewPicture = true; - videoStop(stream, $scope.videoPrim, $scope.videoSec); }, delayTotal); }; - var videoStop = function(stream, video1, video2) { + var videoStop = function(stream, video) { if (stream) { - video1.pause(); - video2.pause(); + video.pause(); stream.stop(); stream = null; } @@ -89,7 +105,7 @@ define(['jquery', 'underscore', 'text!partials/buddypicture.html'], function($, $scope.showTakePicture = true; localStream = stream; $scope.waitingForPermission = false; - attachMediaStream($scope.videoPrim, stream); + attachMediaStream($scope.video, stream); safeApply($scope); videoAllowed.resolve(true); }, function(error) { @@ -108,7 +124,7 @@ define(['jquery', 'underscore', 'text!partials/buddypicture.html'], function($, $scope.cancelPicture = function() { $scope.showTakePicture = false; $scope.previewPicture = false; - videoStop(localStream, $scope.videoPrim, $scope.videoSec); + videoStop(localStream, $scope.video); }; $scope.retakePicture = function() { @@ -126,17 +142,9 @@ define(['jquery', 'underscore', 'text!partials/buddypicture.html'], function($, }; $scope.setAsProfilePicture = function() { - var videoWidth = $scope.videoSec.videoWidth; - var videoHeight = $scope.videoSec.videoHeight; - var aspectRatio = videoWidth/videoHeight; - if (!aspectRatio) { - // NOTE(longsleep): In Firefox the video size becomes available at sound point later - crap! - console.warn("Unable to compute aspectRatio", aspectRatio); - aspectRatio = 1.3333333333333333; - } - var x = (46 * aspectRatio - 46) / -2; - $scope.canvas.getContext("2d").drawImage($scope.videoSec, x, 0, 46 * aspectRatio, 46); - $scope.user.buddyPicture = $scope.canvas.toDataURL("image/jpeg"); + var x = (46 * getCanvasAspectRatio() - 46) / -2; + $scope.canvasPic.getContext("2d").drawImage($scope.video, x, 0, 46 * getCanvasAspectRatio(), 46); + $scope.user.buddyPicture = $scope.canvasPic.toDataURL("image/jpeg"); console.info("Image size", $scope.user.buddyPicture.length); $scope.cancelPicture(); safeApply($scope); @@ -145,9 +153,9 @@ define(['jquery', 'underscore', 'text!partials/buddypicture.html'], function($, }]; var link = function($scope, $element) { - $scope.videoPrim = $element.find("video#prim").get(0); - $scope.videoSec = $element.find("video#sec").get(0); - $scope.canvas = $element.find("canvas").get(0); + $scope.video = $element.find("video").get(0); + $scope.canvasPic = $element.find("canvas#pic").get(0); + $scope.canvasPrev = $element.find("canvas#prev").get(0); }; return { diff --git a/static/partials/buddypicture.html b/static/partials/buddypicture.html index 40982eef..fde0b54f 100644 --- a/static/partials/buddypicture.html +++ b/static/partials/buddypicture.html @@ -3,9 +3,10 @@