simple ionic timer
Created
May 24, 2016 00:18
-
-
Save CiprianSpiridon/592c6e8a725b23f6304932ae663561bc to your computer and use it in GitHub Desktop.
ionic timer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width"> | |
<title></title> | |
<link href="//code.ionicframework.com/nightly/css/ionic.css" rel="stylesheet"> | |
<script src="//code.ionicframework.com/nightly/js/ionic.bundle.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment.min.js"></script> | |
<!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above | |
<link href="css/ionic.app.css" rel="stylesheet"> | |
--> | |
<!-- ionic/angularjs js --> | |
<script src="lib/ionic/js/ionic.bundle.js"></script> | |
<!-- cordova script (this will be a 404 during development) --> | |
<script src="cordova.js"></script> | |
<!-- your app's js --> | |
<script src="js/app.js"></script> | |
<!-- Moment --> | |
<script src="lib/moment/moment.min.js"></script> | |
<!-- rounded progrssbar for timer on player --> | |
<script src="lib/angular-svg-round-progressbar/roundProgress.min.js"></script> | |
</head> | |
<body ng-app="starter"> | |
<div ng-controller="mainCtrl"> | |
<ion-pane> | |
<ion-header-bar class="bar-light"> | |
<h1 class="title">Timer</h1> | |
</ion-header-bar> | |
<ion-content class="padding"> | |
<!-- Here are the 4 main buttons for the exemple, notice that you only have to pass the number of seconds that you want for the timer --> | |
<span class="button button-outline button-positive button-block icon ion-ios-timer-outline button-rounded" ng-click="modal.show();selectTimer(10)"> 10 sec timer</span> | |
<span class="button button-outline button-dark button-block icon ion-ios-timer-outline button-rounded" ng-click="modal.show();selectTimer(30)"> 30 sec timer</span> | |
<span class="button button-outline button-balanced button-block icon ion-ios-timer-outline button-rounded" ng-click="modal.show();selectTimer(60)"> 1 min timer</span> | |
<span class="button button-outline button-royal button-block icon ion-ios-timer-outline button-rounded" ng-click="modal.show();selectTimer(120)"> 2 min timer</span> | |
</ion-content> | |
</ion-pane> | |
</div> | |
</body> | |
</html> | |
<!-- Here you have the modal that opens once a timer is selected --> | |
<script id="templates/timer.html" type="text/ng-template"> | |
<ion-modal-view> | |
<ion-header-bar class="bar bar-header bar-light"> | |
<h1 class="title">Timer</h1> | |
<button class="button button-clear button-primary" ng-click="modal.hide();stopTimer(true);">Cancel</button> | |
</ion-header-bar> | |
<ion-content class="padding"> | |
<!-- Here you have the timer itself with the progress and the time on the middle, notice the css addded to align it see style.css --> | |
<div class="progress-wrapper"> | |
<div class="progress"> | |
{{humanizeDurationTimer(timer,'s')}} | |
</div> | |
<div round-progress max="timeForTimer" current="timer" clockwise="false" color="#ef473a" rounded="true" class="text-center"></div> | |
</div> | |
<!-- Here you have the different states that the buttons take during the process --> | |
<!-- Before starting --> | |
<div ng-if="!started && !paused && !done"> | |
<div class="row"> | |
<div class="col"> | |
<button class="button button-outline button-balanced button-rounded button-block" ng-click='startTimer()'> | |
Start | |
</button> | |
</div> | |
</div> | |
</div> | |
<!-- Once it is running --> | |
<div ng-if="started && !done"> | |
<div class="row"> | |
<div class="col"> | |
<button class="button button-outline button-energized button-rounded button-block" ng-click='pauseTimer()'> | |
Pause | |
</button> | |
</div> | |
<div class="col"> | |
<button class="button button-outline button-assertive button-rounded button-block" ng-click='stopTimer()'> | |
Reset | |
</button> | |
</div> | |
</div> | |
</div> | |
<!-- Once it is paused --> | |
<div ng-if="!started && paused && !done"> | |
<div class="row"> | |
<div class="col"> | |
<button class="button button-outline button-balanced button-rounded button-block" ng-click='startTimer()'> | |
Continue | |
</button> | |
</div> | |
<div class="col"> | |
<button class="button button-outline button-assertive button-rounded button-block" ng-click='stopTimer()'> | |
Reset | |
</button> | |
</div> | |
</div> | |
</div> | |
<!-- When it has completed --> | |
<div ng-if="done" class="text-center"> | |
<div class="row"> | |
<button class="button button-outline button-balanced button-rounded button-block" ng-click="modal.hide();stopTimer(true);"> | |
Done | |
</button> | |
</div> | |
<div class="text-center"> | |
<i class="ion-ribbon-b bigIcon" style="font-size: 40px;"></i> | |
<br> | |
<h2>Congratulations</h2> | |
</div> | |
</div> | |
</ion-content> | |
</ion-modal-view> | |
</script> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Ionic Starter App | |
// angular.module is a global place for creating, registering and retrieving Angular modules | |
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html) | |
// the 2nd parameter is an array of 'requires' | |
angular.module('starter', ['ionic', 'angular-svg-round-progress']) | |
.run(function($ionicPlatform) { | |
$ionicPlatform.ready(function() { | |
if (window.cordova && window.cordova.plugins.Keyboard) { | |
// Hide the accessory bar by default (remove this to show the accessory bar above the keyboard | |
// for form inputs) | |
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true); | |
// Don't remove this line unless you know what you are doing. It stops the viewport | |
// from snapping when text inputs are focused. Ionic handles this internally for | |
// a much nicer keyboard experience. | |
cordova.plugins.Keyboard.disableScroll(true); | |
} | |
if (window.StatusBar) { | |
StatusBar.styleDefault(); | |
} | |
}); | |
}) | |
.controller('mainCtrl', function($scope, $ionicModal, $timeout) { | |
// Timer | |
var mytimeout = null; // the current timeoutID | |
// actual timer method, counts down every second, stops on zero | |
$scope.onTimeout = function() { | |
if ($scope.timer === 0) { | |
$scope.$broadcast('timer-stopped', 0); | |
$timeout.cancel(mytimeout); | |
return; | |
} | |
$scope.timer--; | |
mytimeout = $timeout($scope.onTimeout, 1000); | |
}; | |
// functions to control the timer | |
// starts the timer | |
$scope.startTimer = function() { | |
mytimeout = $timeout($scope.onTimeout, 1000); | |
$scope.started = true; | |
}; | |
// stops and resets the current timer | |
$scope.stopTimer = function(closingModal) { | |
if (closingModal != true) { | |
$scope.$broadcast('timer-stopped', $scope.timer); | |
} | |
$scope.timer = $scope.timeForTimer; | |
$scope.started = false; | |
$scope.paused = false; | |
$timeout.cancel(mytimeout); | |
}; | |
// pauses the timer | |
$scope.pauseTimer = function() { | |
$scope.$broadcast('timer-stopped', $scope.timer); | |
$scope.started = false; | |
$scope.paused = true; | |
$timeout.cancel(mytimeout); | |
}; | |
// triggered, when the timer stops, you can do something here, maybe show a visual indicator or vibrate the device | |
$scope.$on('timer-stopped', function(event, remaining) { | |
if (remaining === 0) { | |
$scope.done = true; | |
} | |
}); | |
// UI | |
// When you press a timer button this function is called | |
$scope.selectTimer = function(val) { | |
$scope.timeForTimer = val; | |
$scope.timer = val | |
$scope.started = false; | |
$scope.paused = false; | |
$scope.done = false; | |
}; | |
// This function helps to display the time in a correct way in the center of the timer | |
$scope.humanizeDurationTimer = function(input, units) { | |
// units is a string with possible values of y, M, w, d, h, m, s, ms | |
if (input == 0) { | |
return 0; | |
} else { | |
var duration = moment().startOf('day').add(input, units); | |
var format = ""; | |
if (duration.hour() > 0) { | |
format += "H[h] "; | |
} | |
if (duration.minute() > 0) { | |
format += "m[m] "; | |
} | |
if (duration.second() > 0) { | |
format += "s[s] "; | |
} | |
return duration.format(format); | |
} | |
}; | |
// function for the modal | |
$ionicModal.fromTemplateUrl('templates/timer.html', { | |
scope: $scope | |
}).then(function(modal) { | |
$scope.modal = modal; | |
}); | |
}); | |
/* [email protected] 2015-10-21 */ | |
"use strict"; | |
! function() { | |
for (var a = 0, b = ["webkit", "moz"], c = 0; c < b.length && !window.requestAnimationFrame; ++c) window.requestAnimationFrame = window[b[c] + "RequestAnimationFrame"], window.cancelAnimationFrame = window[b[c] + "CancelAnimationFrame"] || window[b[c] + "CancelRequestAnimationFrame"]; | |
window.requestAnimationFrame || (window.requestAnimationFrame = function(b) { | |
var c = (new Date).getTime(), | |
d = Math.max(0, 16 - (c - a)), | |
e = window.setTimeout(function() { | |
b(c + d) | |
}, d); | |
return a = c + d, e | |
}), window.cancelAnimationFrame || (window.cancelAnimationFrame = function(a) { | |
window.clearTimeout(a) | |
}) | |
}(), angular.module("angular-svg-round-progress", []), angular.module("angular-svg-round-progress").constant("roundProgressConfig", { | |
max: 50, | |
semi: !1, | |
rounded: !1, | |
responsive: !1, | |
clockwise: !0, | |
radius: 100, | |
color: "#45ccce", | |
bgcolor: "#eaeaea", | |
stroke: 15, | |
duration: 800, | |
animation: "easeOutCubic", | |
offset: 0 | |
}), angular.module("angular-svg-round-progress").service("roundProgressService", [function() { | |
var a = {}, | |
b = angular.isNumber, | |
c = document.head.querySelector("base"); | |
a.resolveColor = c && c.href ? function(a) { | |
var b = a.indexOf("#"); | |
return b > -1 && a.indexOf("url") > -1 ? a.slice(0, b) + window.location.href + a.slice(b) : a | |
} : function(a) { | |
return a | |
}, a.isSupported = !(!document.createElementNS || !document.createElementNS("http://www.w3.org/2000/svg", "svg").createSVGRect); | |
var d = function(a, b, c, d) { | |
var e = (d - 90) * Math.PI / 180; | |
return { | |
x: a + c * Math.cos(e), | |
y: b + c * Math.sin(e) | |
} | |
}; | |
return a.toNumber = function(a) { | |
return b(a) ? a : parseFloat((a + "").replace(",", ".")) | |
}, a.getOffset = function(b, c) { | |
var d = +c.offset || 0; | |
if ("inherit" === c.offset) | |
for (var e, f = b; !f.hasClass("round-progress-wrapper");) a.isDirective(f) && (e = f.scope().$parent.getOptions(), d += (+e.offset || 0) + (+e.stroke || 0)), f = f.parent(); | |
return d | |
}, a.updateState = function(a, b, c, e, f, g) { | |
if (!f) return e; | |
var h = a > 0 ? Math.min(a, b) : 0, | |
i = g ? 180 : 359.9999, | |
j = 0 === b ? 0 : h / b * i, | |
k = f / 2, | |
l = d(k, k, c, j), | |
m = d(k, k, c, 0), | |
n = 180 >= j ? "0" : "1", | |
o = ["M", l.x, l.y, "A", c, c, 0, n, 0, m.x, m.y].join(" "); | |
return e.attr("d", o) | |
}, a.isDirective = function(a) { | |
return a && a.length ? "undefined" != typeof a.attr("round-progress") || "round-progress" === a[0].nodeName.toLowerCase() : !1 | |
}, a.animations = { | |
linearEase: function(a, b, c, d) { | |
return c * a / d + b | |
}, | |
easeInQuad: function(a, b, c, d) { | |
return c * (a /= d) * a + b | |
}, | |
easeOutQuad: function(a, b, c, d) { | |
return -c * (a /= d) * (a - 2) + b | |
}, | |
easeInOutQuad: function(a, b, c, d) { | |
return (a /= d / 2) < 1 ? c / 2 * a * a + b : -c / 2 * (--a * (a - 2) - 1) + b | |
}, | |
easeInCubic: function(a, b, c, d) { | |
return c * (a /= d) * a * a + b | |
}, | |
easeOutCubic: function(a, b, c, d) { | |
return c * ((a = a / d - 1) * a * a + 1) + b | |
}, | |
easeInOutCubic: function(a, b, c, d) { | |
return (a /= d / 2) < 1 ? c / 2 * a * a * a + b : c / 2 * ((a -= 2) * a * a + 2) + b | |
}, | |
easeInQuart: function(a, b, c, d) { | |
return c * (a /= d) * a * a * a + b | |
}, | |
easeOutQuart: function(a, b, c, d) { | |
return -c * ((a = a / d - 1) * a * a * a - 1) + b | |
}, | |
easeInOutQuart: function(a, b, c, d) { | |
return (a /= d / 2) < 1 ? c / 2 * a * a * a * a + b : -c / 2 * ((a -= 2) * a * a * a - 2) + b | |
}, | |
easeInQuint: function(a, b, c, d) { | |
return c * (a /= d) * a * a * a * a + b | |
}, | |
easeOutQuint: function(a, b, c, d) { | |
return c * ((a = a / d - 1) * a * a * a * a + 1) + b | |
}, | |
easeInOutQuint: function(a, b, c, d) { | |
return (a /= d / 2) < 1 ? c / 2 * a * a * a * a * a + b : c / 2 * ((a -= 2) * a * a * a * a + 2) + b | |
}, | |
easeInSine: function(a, b, c, d) { | |
return -c * Math.cos(a / d * (Math.PI / 2)) + c + b | |
}, | |
easeOutSine: function(a, b, c, d) { | |
return c * Math.sin(a / d * (Math.PI / 2)) + b | |
}, | |
easeInOutSine: function(a, b, c, d) { | |
return -c / 2 * (Math.cos(Math.PI * a / d) - 1) + b | |
}, | |
easeInExpo: function(a, b, c, d) { | |
return 0 == a ? b : c * Math.pow(2, 10 * (a / d - 1)) + b | |
}, | |
easeOutExpo: function(a, b, c, d) { | |
return a == d ? b + c : c * (-Math.pow(2, -10 * a / d) + 1) + b | |
}, | |
easeInOutExpo: function(a, b, c, d) { | |
return 0 == a ? b : a == d ? b + c : (a /= d / 2) < 1 ? c / 2 * Math.pow(2, 10 * (a - 1)) + b : c / 2 * (-Math.pow(2, -10 * --a) + 2) + b | |
}, | |
easeInCirc: function(a, b, c, d) { | |
return -c * (Math.sqrt(1 - (a /= d) * a) - 1) + b | |
}, | |
easeOutCirc: function(a, b, c, d) { | |
return c * Math.sqrt(1 - (a = a / d - 1) * a) + b | |
}, | |
easeInOutCirc: function(a, b, c, d) { | |
return (a /= d / 2) < 1 ? -c / 2 * (Math.sqrt(1 - a * a) - 1) + b : c / 2 * (Math.sqrt(1 - (a -= 2) * a) + 1) + b | |
}, | |
easeInElastic: function(a, b, c, d) { | |
var e = 1.70158, | |
f = 0, | |
g = c; | |
return 0 == a ? b : 1 == (a /= d) ? b + c : (f || (f = .3 * d), g < Math.abs(c) ? (g = c, e = f / 4) : e = f / (2 * Math.PI) * Math.asin(c / g), -(g * Math.pow(2, 10 * (a -= 1)) * Math.sin((a * d - e) * (2 * Math.PI) / f)) + b) | |
}, | |
easeOutElastic: function(a, b, c, d) { | |
var e = 1.70158, | |
f = 0, | |
g = c; | |
return 0 == a ? b : 1 == (a /= d) ? b + c : (f || (f = .3 * d), g < Math.abs(c) ? (g = c, e = f / 4) : e = f / (2 * Math.PI) * Math.asin(c / g), g * Math.pow(2, -10 * a) * Math.sin((a * d - e) * (2 * Math.PI) / f) + c + b) | |
}, | |
easeInOutElastic: function(a, b, c, d) { | |
var e = 1.70158, | |
f = 0, | |
g = c; | |
return 0 == a ? b : 2 == (a /= d / 2) ? b + c : (f || (f = d * (.3 * 1.5)), g < Math.abs(c) ? (g = c, e = f / 4) : e = f / (2 * Math.PI) * Math.asin(c / g), 1 > a ? -.5 * (g * Math.pow(2, 10 * (a -= 1)) * Math.sin((a * d - e) * (2 * Math.PI) / f)) + b : g * Math.pow(2, -10 * (a -= 1)) * Math.sin((a * d - e) * (2 * Math.PI) / f) * .5 + c + b) | |
}, | |
easeInBack: function(a, b, c, d, e) { | |
return void 0 == e && (e = 1.70158), c * (a /= d) * a * ((e + 1) * a - e) + b | |
}, | |
easeOutBack: function(a, b, c, d, e) { | |
return void 0 == e && (e = 1.70158), c * ((a = a / d - 1) * a * ((e + 1) * a + e) + 1) + b | |
}, | |
easeInOutBack: function(a, b, c, d, e) { | |
return void 0 == e && (e = 1.70158), (a /= d / 2) < 1 ? c / 2 * (a * a * (((e *= 1.525) + 1) * a - e)) + b : c / 2 * ((a -= 2) * a * (((e *= 1.525) + 1) * a + e) + 2) + b | |
}, | |
easeInBounce: function(b, c, d, e) { | |
return d - a.animations.easeOutBounce(e - b, 0, d, e) + c | |
}, | |
easeOutBounce: function(a, b, c, d) { | |
return (a /= d) < 1 / 2.75 ? c * (7.5625 * a * a) + b : 2 / 2.75 > a ? c * (7.5625 * (a -= 1.5 / 2.75) * a + .75) + b : 2.5 / 2.75 > a ? c * (7.5625 * (a -= 2.25 / 2.75) * a + .9375) + b : c * (7.5625 * (a -= 2.625 / 2.75) * a + .984375) + b | |
}, | |
easeInOutBounce: function(b, c, d, e) { | |
return e / 2 > b ? .5 * a.animations.easeInBounce(2 * b, 0, d, e) + c : .5 * a.animations.easeOutBounce(2 * b - e, 0, d, e) + .5 * d + c | |
} | |
}, a | |
}]), angular.module("angular-svg-round-progress").directive("roundProgress", ["$window", "roundProgressService", "roundProgressConfig", function(a, b, c) { | |
var d = { | |
restrict: "EA", | |
replace: !0, | |
transclude: !0, | |
scope: { | |
current: "=", | |
max: "=", | |
semi: "=", | |
rounded: "=", | |
clockwise: "=", | |
responsive: "=", | |
radius: "@", | |
color: "@", | |
bgcolor: "@", | |
stroke: "@", | |
duration: "@", | |
animation: "@", | |
offset: "@" | |
} | |
}; | |
return b.isSupported ? angular.extend(d, { | |
link: function(e, f) { | |
var g, h, i = !f.hasClass("round-progress-wrapper"), | |
j = i ? f : f.find("svg").eq(0), | |
k = j.find("path").eq(0), | |
l = j.find("circle").eq(0), | |
m = angular.copy(c); | |
e.getOptions = function() { | |
return m | |
}; | |
var n = function() { | |
var a = m.semi, | |
c = m.responsive, | |
d = +m.radius || 0, | |
e = +m.stroke, | |
g = 2 * d, | |
h = d - e / 2 - b.getOffset(f, m); | |
j.css({ | |
top: 0, | |
left: 0, | |
position: c ? "absolute" : "static", | |
width: c ? "100%" : g + "px", | |
height: c ? "100%" : (a ? d : g) + "px", | |
overflow: "hidden" | |
}), i || (j[0].setAttribute("viewBox", "0 0 " + g + " " + (a ? d : g)), f.css({ | |
width: c ? "100%" : "auto", | |
position: "relative", | |
"padding-bottom": c ? a ? "50%" : "100%" : 0 | |
})), f.css({ | |
width: c ? "100%" : "auto", | |
position: "relative", | |
"padding-bottom": c ? a ? "50%" : "100%" : 0 | |
}), k.css({ | |
stroke: b.resolveColor(m.color), | |
"stroke-width": e, | |
"stroke-linecap": m.rounded ? "round" : "butt" | |
}), a ? k.attr("transform", m.clockwise ? "translate(0," + g + ") rotate(-90)" : "translate(" + g + ", " + g + ") rotate(90) scale(-1, 1)") : k.attr("transform", m.clockwise ? "" : "scale(-1, 1) translate(" + -g + " 0)"), l.attr({ | |
cx: d, | |
cy: d, | |
r: h >= 0 ? h : 0 | |
}).css({ | |
stroke: b.resolveColor(m.bgcolor), | |
"stroke-width": e | |
}) | |
}, | |
o = function(c, d, e) { | |
var h = b.toNumber(m.max || 0), | |
i = c > 0 ? a.Math.min(c, h) : 0, | |
j = d === i || 0 > d ? 0 : d || 0, | |
l = i - j, | |
n = b.animations[m.animation], | |
o = new a.Date, | |
p = +m.duration || 0, | |
q = e || c > h && d > h || 0 > c && 0 > d || 25 > p, | |
r = m.radius, | |
s = r - m.stroke / 2 - b.getOffset(f, m), | |
t = 2 * r, | |
u = m.semi; | |
q ? b.updateState(i, h, s, k, t, u) : (a.cancelAnimationFrame(g), function v() { | |
var c = a.Math.min(new Date - o, p); | |
b.updateState(n(c, j, l, p), h, s, k, t, u), p > c && (g = a.requestAnimationFrame(v)) | |
}()) | |
}, | |
p = Object.keys(d.scope).filter(function(a) { | |
return "current" !== a | |
}); | |
e.$watchGroup(p, function(a) { | |
for (var b = 0; b < a.length; b++) "undefined" != typeof a[b] && (m[p[b]] = a[b]); | |
n(), e.$broadcast("$parentOffsetChanged"), "inherit" !== m.offset || h ? "inherit" !== m.offset && h && h() : h = e.$on("$parentOffsetChanged", function() { | |
o(e.current, e.current, !0), n() | |
}) | |
}), e.$watchGroup(["current", "max", "animation", "duration", "radius", "stroke", "semi", "offset"], function(a, c) { | |
o(b.toNumber(a[0]), b.toNumber(c[0])) | |
}) | |
}, | |
template: function(a) { | |
for (var c = a.parent(), d = "round-progress", e = ['<svg class="' + d + '" xmlns="http://www.w3.org/2000/svg">', '<circle fill="none"/>', '<path fill="none"/>', "<g ng-transclude></g>", "</svg>"]; c.length && !b.isDirective(c);) c = c.parent(); | |
return c && c.length || (e.unshift('<div class="round-progress-wrapper">'), e.push("</div>")), e.join("\n") | |
} | |
}) : angular.extend(d, { | |
template: '<div class="round-progress" ng-transclude></div>' | |
}) | |
}]); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*progress time text on middle of circle*/ | |
.progress-wrapper { | |
position: relative; | |
margin: 20px auto; | |
font-size: 21px; | |
} | |
.progress { | |
position: absolute; | |
width: 100%; | |
height: 100%; | |
line-height: 9em; | |
font-size: 1em; | |
text-align: center; | |
font-weight: 100; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment