Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial commit #5

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 149 additions & 0 deletions Spinner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* @license MPL 2.0
* @copyright Daniel Zaner 2014
*/

define(function(require, exports, module) {
var View = require('famous/core/View');
var RenderNode = require('famous/core/RenderNode');
var Surface = require('famous/core/Surface');
var EventHandler = require('famous/core/EventHandler');
var Modifier = require('famous/core/Modifier');
var Transform = require('famous/core/Transform');
var StateModifier = require('famous/modifiers/StateModifier');
var RenderController = require('famous/views/RenderController');
var Timer = require('famous/utilities/Timer');

/**
* A RenderController for rendering a 'spinner' -- a UI element to indicate that
* an action is "in progress" and that the user should wait
*
* Note: If a Spinner is positioned using an "origin" transform, the Spinner's ticks
* will be positioned from their centers rather than a corner. Use the "originCompensation"
* option to normalize the Spinner's radius.
*
* @class Spinner
* @extends RenderController
* @constructor
*
* @param {object} options overrides of deault options
* @param {[Number, Number]} [options.size=[30,30]] Sets the size of the Spinner; Note: width should equal height
* @param {Number} [options.ticks=12] Sets number of tick marks used to build the Spinner
* @param {Number} [options.speed=100] Speed of the Spinners apparent rotation in milliseconds between tick opacity changes
* @param {boolean} [options.originCompensation=false] Is radius compensation needed because Spinner is positioned via an "origin" transform
* @param {object} [options.properties.color='grey'] Color of the Spinner
*
*/
function Spinner(options) {
RenderController.apply(this, arguments);
if (options) this.setOptions(options);

this.spinnerState = Spinner.OFF;
this.tickOpacityModifiers = [];

var tickWidth = Math.round(this.options.size[0] * 0.05);
var tickHeight = Math.round(this.options.size[1] * 0.3);
var angleIncrement = 360 / this.options.ticks;
var radiusCompensation = (this.options.originCompensation && (tickHeight / 2)) || 0;
var circleRadius = this.options.size[0] * 0.55 - radiusCompensation;

this.renderNode = new RenderNode();
for (var i = 0; i < this.options.ticks; i++) {
var p = {};
p.x = (circleRadius * Math.cos((angleIncrement * i) * (Math.PI / 180)));
p.y = (circleRadius * Math.sin((angleIncrement * i) * (Math.PI / 180)));
var rotationModifier = new StateModifier({
transform: Transform.rotateZ((Math.PI / 2) + (Math.PI / this.options.ticks * 2 * i))
});
var opacityModifier = new StateModifier({
transform: Transform.translate(p.x, p.y, 0),
opacity: (i / this.options.ticks + 0.1)
});
this.tickOpacityModifiers.push(opacityModifier);
var surface = new Surface({
size: [tickWidth, tickHeight],
properties: {
backgroundColor: this.options.properties.color
}
});
this.renderNode.add(opacityModifier).add(rotationModifier).add(surface);
}
}

Spinner.OFF = 0;
Spinner.ON = 1;

Spinner.prototype = Object.create(RenderController.prototype);
Spinner.prototype.constructor = Spinner;

Spinner.DEFAULT_OPTIONS = {
size: [30, 30],
ticks: 12,
speed: 100,
originCompensation: false,
properties: {
color: 'grey'
}
};

/**
* Set internal options, overriding any default options
*
* @method setOptions
* @param {Object} [options] overrides of default options
*/
Spinner.prototype.setOptions = function setOptions(options) {
if (options.size !== undefined) this.options.size = options.size;
if (options.ticks !== undefined) this.options.ticks = options.ticks;
if (options.speed !== undefined) this.options.speed = options.speed;
if (options.originCompensation !== undefined) this.options.originCompensation = options.originCompensation;
if (options.properties !== undefined) {
if (this.options.properties === undefined) this.options.properties = {};
if (options.properties.color !== undefined) this.options.properties.color = options.properties.color;
}
};

/**
* Show the spinner and trigger the rotation animation
*
* @method start
*/
Spinner.prototype.start = function start() {
this.spinnerState = Spinner.ON;
this.show(this.renderNode);
Timer.setTimeout(this.incrementSpinner.bind(this), this.options.speed);
};

/**
* Hide the spinner and halt the rotation animation
*
* @method stop
*/
Spinner.prototype.stop = function stop() {
this.spinnerState = Spinner.OFF;
this.hide(this.renderNode);
};


//
/**
* Increment the spinner's ticks' opacity to produce a rotation animation
*
* @method incrementSpinner
*/

Spinner.prototype.incrementSpinner = function incrementSpinner() {
this.tickOpacityModifiers.push(this.tickOpacityModifiers.shift());
for (var i=0; i < this.tickOpacityModifiers.length; i++) {
this.tickOpacityModifiers[i].setOpacity(i / this.options.ticks + 0.1);
}
if (this.spinnerState == Spinner.ON) {
Timer.setTimeout(this.incrementSpinner.bind(this), this.options.speed);
}
};

module.exports = Spinner;
});