From 9f824de49de73f4341fe2d1b8475bbc9e238d031 Mon Sep 17 00:00:00 2001 From: Phil Date: Mon, 3 Apr 2017 16:42:53 +1000 Subject: [PATCH] feat(background): make background a service. Change to use queue of backgrounds to make it robust against quickly changing backgrounds --- .../citizenScience/bristlebird/bristlebird.js | 10 +- .../directives/background/background.js | 64 ----------- .../background/_background.scss | 10 +- .../services/background/background.js | 104 ++++++++++++++++++ 4 files changed, 117 insertions(+), 71 deletions(-) delete mode 100644 src/components/directives/background/background.js rename src/components/{directives => services}/background/_background.scss (59%) create mode 100644 src/components/services/background/background.js diff --git a/src/app/citizenScience/bristlebird/bristlebird.js b/src/app/citizenScience/bristlebird/bristlebird.js index b9880af1..892052a6 100644 --- a/src/app/citizenScience/bristlebird/bristlebird.js +++ b/src/app/citizenScience/bristlebird/bristlebird.js @@ -23,7 +23,8 @@ class BristlebirdController { MediaModel, UserProfile, UserProfileEvents, - CitizenScienceCommon) { + CitizenScienceCommon, + bgImage) { var self = this; @@ -156,7 +157,8 @@ class BristlebirdController { console.log("load audio for sample " + $scope.currentSampleNum); var currentSample = $scope.samples[$scope.currentSampleNum]; self.showAudio(currentSample.recordingId, currentSample.startOffset, self.sampleDuration); - $rootScope.bgImageSource = self.backgroundPaths[$scope.currentSampleNum % (self.backgroundPaths.length - 1)]; + var bgPath = self.backgroundPaths[$scope.currentSampleNum % (self.backgroundPaths.length - 1)]; + bgImage.curBg = bgPath; } }); @@ -199,7 +201,8 @@ angular "bawApp.citizenScience.common", "bawApp.components.citizenScienceLabels", "bawApp.components.citizenScienceExamples", - "bawApp.components.onboarding" + "bawApp.components.onboarding", + "bawApp.components.background" ]) .controller( "BristlebirdController", @@ -215,6 +218,7 @@ angular "UserProfile", "UserProfileEvents", "CitizenScienceCommon", + "bgImage", BristlebirdController ]) .controller( diff --git a/src/components/directives/background/background.js b/src/components/directives/background/background.js deleted file mode 100644 index 0a95e65c..00000000 --- a/src/components/directives/background/background.js +++ /dev/null @@ -1,64 +0,0 @@ -angular.module("bawApp.components.background", []) - .component("background",{ - template: "
" + - "
", - controller: ["$scope", "$rootScope", "$window", "$element", "$interval", function ($scope, $rootScope, $window, $element, $interval) { - - var self = this; - - /** - * Loads the old url into the back bg div (so, two copies of the same image one behind the other) - * Preloads image. When loaded, sets the state to 'ready', which is opacity 1 with transition. - * Then, loads the new url into the front bg div. - * Sets state of the front div to preloading, which is opacity 0 with no transition. - * This will continue to show the old bg in the bgBack div. - * This will fade in the new bg image infront of the old one. - * @param newUrl - * @param oldUrl - */ - - self.setBg = function (newUrl, oldUrl) { - - $scope.bgBack = oldUrl; - $scope.state = "preloading"; - - var preload = new Image(); - preload.src = newUrl; - - if (preload.complete) { - self.bgLoaded(newUrl); - } else { - preload.addEventListener("load", function (e) { - self.bgLoaded(e.srcElement.src); - this.remove(); - }); - preload.addEventListener("error", function() { - console.warn("Error loading background image", this); - this.remove(); - }); - } - - }; - - /** - * Updates the src of the front image and sets the state to ready, which - * switches the opacity to 1. Called when the preloading is done. - * @param newUrl - */ - self.bgLoaded = function (newUrl) { - $scope.bgFront = newUrl; - setTimeout(function () { - $scope.state = "ready"; - }, 100); - }; - - $rootScope.$watch("bgImageSource", function (newval, oldval) { - if (typeof newval !== "string") { - return; - } - self.setBg(newval, oldval); - - }); - - }] - }); diff --git a/src/components/directives/background/_background.scss b/src/components/services/background/_background.scss similarity index 59% rename from src/components/directives/background/_background.scss rename to src/components/services/background/_background.scss index 58e8328b..c51a23cc 100644 --- a/src/components/directives/background/_background.scss +++ b/src/components/services/background/_background.scss @@ -15,14 +15,16 @@ &.preloading { transition: none; + -moz-transition: none; + -webkit-transition: none; opacity: 0; } - &.ready { + &.fadeIn, &.done { opacity: 1; - transition: opacity .5s ease-in-out; - -moz-transition: opacity .5s ease-in-out; - -webkit-transition: opacity .5s ease-in-out; + transition: opacity .9s ease-in-out; + -moz-transition: opacity .9s ease-in-out; + -webkit-transition: opacity .9s ease-in-out; } diff --git a/src/components/services/background/background.js b/src/components/services/background/background.js new file mode 100644 index 00000000..3cdf4fda --- /dev/null +++ b/src/components/services/background/background.js @@ -0,0 +1,104 @@ +angular.module("bawApp.components.background", []) + .service("bgImage", function() { + var curBg = ""; + return { + curBg: curBg + }; + }) + .component("background",{ + template: "
", + controller: ["$scope", "bgImage", function ($scope, bgImage) { + + var self = this; + + $scope.bgs = []; + + /** + * Watches for changes to the bgImage service. When a change is detected it + * adds to the bgs array on scope. The array holds the url and the 'state'. State can be + * preloading, fadeIn, done and finished. + * preloading: image is preloading. Set the opacity to 0 + * fadeIn: image has been preloaded, fade it in. + * done: image is finished fading in. Anything behind it can be removed. + * finished: is behind an image with state done. Remove it from dom. + * The bgs array is bound to scope in a repeat. New images can be added quicker than they can fade in without problem + * because it just adds them over the top of the existing fading-in images. + * @param newUrl + * @param oldUrl + */ + + self.setBg = function () { + + if (typeof bgImage.curBg !== "string" || bgImage.curBg.length === 0) { + return; + } + + $scope.bgs.push({ + url : bgImage.curBg, + state : "preloading" + }); + + var curBgNum = $scope.bgs.length - 1; + + var preload = new Image(); + preload.src = bgImage.curBg; + + if (preload.complete) { + self.bgLoaded(curBgNum); + } else { + preload.addEventListener("load", function (e) { + self.bgLoaded(curBgNum); + this.remove(); + }); + preload.addEventListener("error", function() { + console.warn("Error loading background image", this); + this.remove(); + }); + } + + }; + + /** + * Updates the src of the front image and sets the state to ready, which + * switches the opacity to 1. Called when the preloading is done. + * @param newUrl + */ + self.bgLoaded = function (bgNum) { + setTimeout(function () { + $scope.bgs[bgNum].state = "fadeIn"; + }, 50); + setTimeout(function () { + + // because this is a timeout, it won't the state change won't be picked up by the bound template + // but it doesn't matter. This is just for checking what can be removed. + // timeout duration must be longer than the css fade in transition. + $scope.bgs[bgNum].state = "done"; + self.cleanupBgs(); + }, 1000); + }; + + + /** + * Removes all bgs from the list that are before (lower index) any with state 'done' + */ + self.cleanupBgs = function () { + + var discard = false; + for (var i = $scope.bgs.length - 1; i >= 0; i--) { + + if (discard) { + $scope.bgs[i].state = "finished"; + } else if ($scope.bgs[i].state === "done") { + discard = true; + } + } + }; + + $scope.$watch(function () { + return bgImage.curBg; + }, function (newVal, oldVal) { + self.setBg(); + }); + + }] + });