Skip to content
This repository has been archived by the owner on Sep 5, 2024. It is now read-only.

Commit

Permalink
feat(circular_progress): Add circular progress component
Browse files Browse the repository at this point in the history
This commit adds a new component, material-circular-progress, which enables the use of both determinate and indeterminate circular progress indicators.

Fixes Issue #192
Closes #365
  • Loading branch information
EisenbergEffect authored and ThomasBurleson committed Oct 5, 2014
1 parent 5847006 commit 07d5653
Show file tree
Hide file tree
Showing 10 changed files with 315 additions and 1 deletion.
1 change: 1 addition & 0 deletions config/build.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ module.exports = {
'src/components/whiteframe/whiteframe.js',
'src/components/divider/divider.js',
'src/components/linearProgress/linearProgress.js',
'src/components/circularProgress/circularProgress.js',

// Non-visual Components
'src/components/swipe/swipe.js',
Expand Down
1 change: 1 addition & 0 deletions src/components/circularProgress/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Circular progress indicators, created with the `<material-circular-progress>` directive.
139 changes: 139 additions & 0 deletions src/components/circularProgress/_circularProgress.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
$circle-size:48px;
$circle-background:transparent;
$circle-color:$color-blue-500;
$inset-size:36px;
$inset-color:white;
$transition-length:.3s;
$shadow:6px 6px 10px rgba(0, 0, 0, 0.2);
material-circular-progress {
display: block;
width: $circle-size + 6;
height: $circle-size + 6;
background-color: $circle-background;
border-radius: 50%;
padding: 3px;

.wrapper1, .wrapper2 {
width: $circle-size;
height: $circle-size;
position: absolute;
border-radius: 50%;
}

.circle {
.mask, .fill, .shadow {
width: $circle-size;
height: $circle-size;
position: absolute;
border-radius: 50%;
}

.shadow { }

.mask, .fill {
-webkit-backface-visibility: hidden;
transition: -webkit-transform $transition-length;
transition: -ms-transform $transition-length;
transition: transform $transition-length;
}

.mask {
clip: rect(0px, $circle-size, $circle-size, $circle-size/2);
.fill {
clip: rect(0px, $circle-size/2, $circle-size, 0px);
background-color: $circle-color;
}
}
}

.inset {
width: $inset-size;
height: $inset-size;
position: absolute;
margin-left: ($circle-size - $inset-size)/2;
margin-top: ($circle-size - $inset-size)/2;
background-color: $inset-color;
border-radius: 50%;
}

&[mode=indeterminate] {
.wrapper1, .wrapper2 {
-ms-transform-origin: 50% 50%; /* IE 9 */
webkit-transform-origin: 50% 50%; /* Chrome, Safari, Opera */
transform-origin: 50% 50%;
}

.wrapper1{
@include animation(indeterminate_rotate1 3s infinite linear);
}

.wrapper2{
@include animation(indeterminate_rotate2 1.5s infinite linear);
}

.fill, .mask.full{
@include animation(indeterminate_size_fill 1.5s infinite linear);
}

.fill.fix {
@include animation(indeterminate_size_fix 1.5s infinite linear);
}
}
}

@include keyframes(indeterminate_rotate1) {
0%{
@include transform(rotate(0deg));
}
100%{
@include transform(rotate(360deg));
}
}

@include keyframes(indeterminate_rotate2) {
0%{
@include transform(rotate(0deg));
}
70%{
@include transform(rotate(0deg));
}
100%{
@include transform(rotate(360deg));
}
}

@include keyframes(indeterminate_size_fill) {
0%{
@include transform(rotate(5deg));
}
10%{
@include transform(rotate(5deg));
}
50%{
@include transform(rotate(135deg));
}
70%{
@include transform(rotate(135deg));
}
100%{
@include transform(rotate(5deg));
}
}

@include keyframes(indeterminate_size_fix) {
0%{
@include transform(rotate(10deg));
}
10%{
@include transform(rotate(10deg));
}
50%{
@include transform(rotate(270deg));
}
70%{
@include transform(rotate(270deg));
}
100%{
@include transform(rotate(10deg));
}
}
120 changes: 120 additions & 0 deletions src/components/circularProgress/circularProgress.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/**
* @ngdoc module
* @name material.components.circularProgress
* @description Circular Progress module!
*/
angular.module('material.components.circularProgress', [
'material.animations',
'material.services.aria'
])
.directive('materialCircularProgress', [
'$$rAF',
'$materialEffects',
MaterialCircularProgressDirective
]);

/**
* @ngdoc directive
* @name materialCircularProgress
* @module material.components.circularProgress
* @restrict E
*
* @description
* The circular progress directive is used to make loading content in your app as delightful and painless as possible by minimizing the amount of visual change a user sees before they can view and interact with content.
*
* For operations where the percentage of the operation completed can be determined, use a determinate indicator. They give users a quick sense of how long an operation will take.
*
* For operations where the user is asked to wait a moment while something finishes up, and it’s not necessary to expose what's happening behind the scenes and how long it will take, use an indeterminate indicator.
*
* @param {string} mode Select from one of two modes: determinate and indeterminate.
* @param {number=} value In determinate mode, this number represents the percentage of the circular progress. Default: 0
* @param {number=} diameter This specifies the diamter of the circular progress. Default: 48
*
* @usage
* <hljs lang="html">
* <material-circular-progress mode="determinate" value="..."></material-circular-progress>
*
* <material-circular-progress mode="determinate" ng-value="..."></material-circular-progress>
*
* <material-circular-progress mode="determinate" value="..." diameter="100"></material-circular-progress>
*
* <material-circular-progress mode="indeterminate"></material-circular-progress>
* </hljs>
*/
function MaterialCircularProgressDirective($$rAF, $materialEffects) {
var fillRotations = new Array(101),
fixRotations = new Array(101);

for (var i = 0; i < 101; i++) {
var percent = i / 100;
var rotation = Math.floor(percent * 180);

fillRotations[i] = 'rotate(' + rotation.toString() + 'deg)';
fixRotations[i] = 'rotate(' + (rotation * 2).toString() + 'deg)';
}

return {
restrict: 'E',
template:
'<div class="wrapper1"><div class="wrapper2"><div class="circle">' +
'<div class="mask full">' +
'<div class="fill"></div>' +
'</div>' +
'<div class="mask half">' +
'<div class="fill"></div>' +
'<div class="fill fix"></div>' +
'</div>' +
'<div class="shadow"></div>' +
'</div>' +
'<div class="inset"></div></div></div>',
compile: compile
};

function compile(tElement, tAttrs, transclude) {
tElement.attr('aria-valuemin', 0);
tElement.attr('aria-valuemax', 100);
tElement.attr('role', 'progressbar');

return postLink;
}

function postLink(scope, element, attr) {
var circle = element[0],
fill = circle.querySelectorAll('.fill, .mask.full'),
fix = circle.querySelectorAll('.fill.fix'),
i, clamped, fillRotation, fixRotation;

var diameter = attr.diameter || 48;
var scale = diameter/48;

circle.style[$materialEffects.TRANSFORM] = 'scale(' + scale.toString() + ')';

attr.$observe('value', function(value) {
clamped = clamp(value);
fillRotation = fillRotations[clamped];
fixRotation = fixRotations[clamped];

element.attr('aria-valuenow', clamped);

for (i = 0; i < fill.length; i++) {
fill[i].style[$materialEffects.TRANSFORM] = fillRotation;
}

for (i = 0; i < fix.length; i++) {
fix[i].style[$materialEffects.TRANSFORM] = fixRotation;
}
});
}

function clamp(value) {
if (value > 100) {
return 100;
}

if (value < 0) {
return 0;
}

return Math.ceil(value || 0);
}
}
18 changes: 18 additions & 0 deletions src/components/circularProgress/circularProgress.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
describe('materialCircularProgress', function() {
beforeEach(module('material.components.circularProgress'));

it('should update aria-valuenow', inject(function($compile, $rootScope) {
var element = $compile('<div>' +
'<material-circular-progress value="{{progress}}">' +
'</material-circular-progress>' +
'</div>')($rootScope);

$rootScope.$apply(function() {
$rootScope.progress = 50;
});

var progress = element.find('material-circular-progress');

expect(progress.eq(0).attr('aria-valuenow')).toEqual('50');
}));
});
7 changes: 7 additions & 0 deletions src/components/circularProgress/demo1/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<div ng-controller="AppCtrl" layout="vertical" layout-padding>
<h3>Determinate</h3>
<material-circular-progress mode="determinate" value="{{determinateValue}}"></material-circular-progress>

<h3>Indeterminate</h3>
<material-circular-progress mode="indeterminate"></material-circular-progress>
</div>
14 changes: 14 additions & 0 deletions src/components/circularProgress/demo1/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
angular.module('circularProgressDemo1', ['ngMaterial'])
.controller('AppCtrl', ['$scope', '$interval',
function($scope, $interval) {
$scope.mode = 'query';
$scope.determinateValue = 30;

$interval(function() {
$scope.determinateValue += 1;
if ($scope.determinateValue > 100) {
$scope.determinateValue = 30;
}
}, 100, 0, true);
}
]);
3 changes: 3 additions & 0 deletions src/components/circularProgress/demo1/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
body {
padding: 20px;
}
10 changes: 10 additions & 0 deletions src/components/circularProgress/module.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"module": "material.components.circularProgress",
"name": "Circular Progress",
"demos": {
"demo1": {
"name": "Circular Progress Basic Usage",
"files": ["demo1/*"]
}
}
}
3 changes: 2 additions & 1 deletion src/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,5 @@
"components/list/list",
"components/divider/divider",
"components/whiteframe/whiteframe",
"components/linearProgress/linearProgress";
"components/linearProgress/linearProgress",
"components/circularProgress/circularProgress";

0 comments on commit 07d5653

Please sign in to comment.