123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415 |
- import Super from './super';
- import * as u from './utils';
- ///////////////////////
- /// THE NIPPLE ///
- ///////////////////////
- function Nipple (collection, options) {
- this.identifier = options.identifier;
- this.position = options.position;
- this.frontPosition = options.frontPosition;
- this.collection = collection;
- // Defaults
- this.defaults = {
- size: 100,
- threshold: 0.1,
- color: 'white',
- fadeTime: 250,
- dataOnly: false,
- restJoystick: true,
- restOpacity: 0.5,
- mode: 'dynamic',
- zone: document.body,
- lockX: false,
- lockY: false,
- shape: 'circle'
- };
- this.config(options);
- // Overwrites
- if (this.options.mode === 'dynamic') {
- this.options.restOpacity = 0;
- }
- this.id = Nipple.id;
- Nipple.id += 1;
- this.buildEl()
- .stylize();
- // Nipple's API.
- this.instance = {
- el: this.ui.el,
- on: this.on.bind(this),
- off: this.off.bind(this),
- show: this.show.bind(this),
- hide: this.hide.bind(this),
- add: this.addToDom.bind(this),
- remove: this.removeFromDom.bind(this),
- destroy: this.destroy.bind(this),
- setPosition:this.setPosition.bind(this),
- resetDirection: this.resetDirection.bind(this),
- computeDirection: this.computeDirection.bind(this),
- trigger: this.trigger.bind(this),
- position: this.position,
- frontPosition: this.frontPosition,
- ui: this.ui,
- identifier: this.identifier,
- id: this.id,
- options: this.options
- };
- return this.instance;
- }
- Nipple.prototype = new Super();
- Nipple.constructor = Nipple;
- Nipple.id = 0;
- // Build the dom element of the Nipple instance.
- Nipple.prototype.buildEl = function (options) {
- this.ui = {};
- if (this.options.dataOnly) {
- return this;
- }
- this.ui.el = document.createElement('div');
- this.ui.back = document.createElement('div');
- this.ui.front = document.createElement('div');
- this.ui.el.className = 'nipple collection_' + this.collection.id;
- this.ui.back.className = 'back';
- this.ui.front.className = 'front';
- this.ui.el.setAttribute('id', 'nipple_' + this.collection.id +
- '_' + this.id);
- this.ui.el.appendChild(this.ui.back);
- this.ui.el.appendChild(this.ui.front);
- return this;
- };
- // Apply CSS to the Nipple instance.
- Nipple.prototype.stylize = function () {
- if (this.options.dataOnly) {
- return this;
- }
- var animTime = this.options.fadeTime + 'ms';
- var borderStyle = u.getVendorStyle('borderRadius', '50%');
- var transitStyle = u.getTransitionStyle('transition', 'opacity', animTime);
- var styles = {};
- styles.el = {
- position: 'absolute',
- opacity: this.options.restOpacity,
- display: 'block',
- 'zIndex': 999
- };
- styles.back = {
- position: 'absolute',
- display: 'block',
- width: this.options.size + 'px',
- height: this.options.size + 'px',
- marginLeft: -this.options.size / 2 + 'px',
- marginTop: -this.options.size / 2 + 'px',
- background: this.options.color,
- 'opacity': '.5'
- };
- styles.front = {
- width: this.options.size / 2 + 'px',
- height: this.options.size / 2 + 'px',
- position: 'absolute',
- display: 'block',
- marginLeft: -this.options.size / 4 + 'px',
- marginTop: -this.options.size / 4 + 'px',
- background: this.options.color,
- 'opacity': '.5'
- };
- u.extend(styles.el, transitStyle);
- if(this.options.shape === 'circle'){
- u.extend(styles.back, borderStyle);
- }
- u.extend(styles.front, borderStyle);
- this.applyStyles(styles);
- return this;
- };
- Nipple.prototype.applyStyles = function (styles) {
- // Apply styles
- for (var i in this.ui) {
- if (this.ui.hasOwnProperty(i)) {
- for (var j in styles[i]) {
- this.ui[i].style[j] = styles[i][j];
- }
- }
- }
- return this;
- };
- // Inject the Nipple instance into DOM.
- Nipple.prototype.addToDom = function () {
- // We're not adding it if we're dataOnly or already in dom.
- if (this.options.dataOnly || document.body.contains(this.ui.el)) {
- return this;
- }
- this.options.zone.appendChild(this.ui.el);
- return this;
- };
- // Remove the Nipple instance from DOM.
- Nipple.prototype.removeFromDom = function () {
- if (this.options.dataOnly || !document.body.contains(this.ui.el)) {
- return this;
- }
- this.options.zone.removeChild(this.ui.el);
- return this;
- };
- // Entirely destroy this nipple
- Nipple.prototype.destroy = function () {
- clearTimeout(this.removeTimeout);
- clearTimeout(this.showTimeout);
- clearTimeout(this.restTimeout);
- this.trigger('destroyed', this.instance);
- this.removeFromDom();
- this.off();
- };
- // Fade in the Nipple instance.
- Nipple.prototype.show = function (cb) {
- var self = this;
- if (self.options.dataOnly) {
- return self;
- }
- clearTimeout(self.removeTimeout);
- clearTimeout(self.showTimeout);
- clearTimeout(self.restTimeout);
- self.addToDom();
- self.restCallback();
- setTimeout(function () {
- self.ui.el.style.opacity = 1;
- }, 0);
- self.showTimeout = setTimeout(function () {
- self.trigger('shown', self.instance);
- if (typeof cb === 'function') {
- cb.call(this);
- }
- }, self.options.fadeTime);
- return self;
- };
- // Fade out the Nipple instance.
- Nipple.prototype.hide = function (cb) {
- var self = this;
- if (self.options.dataOnly) {
- return self;
- }
- self.ui.el.style.opacity = self.options.restOpacity;
- clearTimeout(self.removeTimeout);
- clearTimeout(self.showTimeout);
- clearTimeout(self.restTimeout);
- self.removeTimeout = setTimeout(
- function () {
- var display = self.options.mode === 'dynamic' ? 'none' : 'block';
- self.ui.el.style.display = display;
- if (typeof cb === 'function') {
- cb.call(self);
- }
- self.trigger('hidden', self.instance);
- },
- self.options.fadeTime
- );
- if (self.options.restJoystick) {
- const rest = self.options.restJoystick;
- const newPosition = {};
- newPosition.x = rest === true || rest.x !== false ? 0 : self.instance.frontPosition.x;
- newPosition.y = rest === true || rest.y !== false ? 0 : self.instance.frontPosition.y;
- self.setPosition(cb, newPosition);
- }
- return self;
- };
- // Set the nipple to the specified position
- Nipple.prototype.setPosition = function (cb, position) {
- var self = this;
- self.frontPosition = {
- x: position.x,
- y: position.y
- };
- var animTime = self.options.fadeTime + 'ms';
- var transitStyle = {};
- transitStyle.front = u.getTransitionStyle('transition',
- ['top', 'left'], animTime);
- var styles = {front: {}};
- styles.front = {
- left: self.frontPosition.x + 'px',
- top: self.frontPosition.y + 'px'
- };
- self.applyStyles(transitStyle);
- self.applyStyles(styles);
- self.restTimeout = setTimeout(
- function () {
- if (typeof cb === 'function') {
- cb.call(self);
- }
- self.restCallback();
- },
- self.options.fadeTime
- );
- };
- Nipple.prototype.restCallback = function () {
- var self = this;
- var transitStyle = {};
- transitStyle.front = u.getTransitionStyle('transition', 'none', '');
- self.applyStyles(transitStyle);
- self.trigger('rested', self.instance);
- };
- Nipple.prototype.resetDirection = function () {
- // Fully rebuild the object to let the iteration possible.
- this.direction = {
- x: false,
- y: false,
- angle: false
- };
- };
- Nipple.prototype.computeDirection = function (obj) {
- var rAngle = obj.angle.radian;
- var angle45 = Math.PI / 4;
- var angle90 = Math.PI / 2;
- var direction, directionX, directionY;
- // Angular direction
- // \ UP /
- // \ /
- // LEFT RIGHT
- // / \
- // /DOWN \
- //
- if (
- rAngle > angle45 &&
- rAngle < (angle45 * 3) &&
- !obj.lockX
- ) {
- direction = 'up';
- } else if (
- rAngle > -angle45 &&
- rAngle <= angle45 &&
- !obj.lockY
- ) {
- direction = 'left';
- } else if (
- rAngle > (-angle45 * 3) &&
- rAngle <= -angle45 &&
- !obj.lockX
- ) {
- direction = 'down';
- } else if (!obj.lockY) {
- direction = 'right';
- }
- // Plain direction
- // UP |
- // _______ | RIGHT
- // LEFT |
- // DOWN |
- if (!obj.lockY) {
- if (rAngle > -angle90 && rAngle < angle90) {
- directionX = 'left';
- } else {
- directionX = 'right';
- }
- }
- if (!obj.lockX) {
- if (rAngle > 0) {
- directionY = 'up';
- } else {
- directionY = 'down';
- }
- }
- if (obj.force > this.options.threshold) {
- var oldDirection = {};
- var i;
- for (i in this.direction) {
- if (this.direction.hasOwnProperty(i)) {
- oldDirection[i] = this.direction[i];
- }
- }
- var same = {};
- this.direction = {
- x: directionX,
- y: directionY,
- angle: direction
- };
- obj.direction = this.direction;
- for (i in oldDirection) {
- if (oldDirection[i] === this.direction[i]) {
- same[i] = true;
- }
- }
- // If all 3 directions are the same, we don't trigger anything.
- if (same.x && same.y && same.angle) {
- return obj;
- }
- if (!same.x || !same.y) {
- this.trigger('plain', obj);
- }
- if (!same.x) {
- this.trigger('plain:' + directionX, obj);
- }
- if (!same.y) {
- this.trigger('plain:' + directionY, obj);
- }
- if (!same.angle) {
- this.trigger('dir dir:' + direction, obj);
- }
- } else {
- this.resetDirection();
- }
- return obj;
- };
- export default Nipple;
|