"use strict";
var Util = require('../util');
var Base = require('../base');
/**
* a snap plugin for xscroll,wich support vertical and horizontal snap.
* @constructor
* @param {object} cfg
* @param {number} cfg.snapColIndex initial col index
* @param {number} cfg.snapRowIndex initial row index
* @param {number} cfg.snapDuration duration for snap animation
* @param {string} cfg.snapEasing easing for snap animation
* @param {number} cfg.snapOffsetLeft an offset from left boundry for snap wich default value is 0
* @param {number} cfg.snapOffsetTop an offset from top boundry for snap wich default value is 0
* @param {boolean} cfg.autoStep which step is based on scroll velocity
* @extends {Base}
*/
var Snap = function(cfg) {
Snap.superclass.constructor.call(this, cfg);
this.userConfig = Util.mix({
snapColIndex: 0,
snapRowIndex: 0,
snapDuration: 500,
snapEasing: "ease",
snapOffsetLeft: 0,
snapOffsetTop: 0,
autoStep: false //autostep
}, cfg);
}
Util.extend(Snap, Base, {
/**
* a pluginId
* @memberOf Snap
* @type {string}
*/
pluginId: "snap",
/**
* plugin initializer
* @memberOf Snap
* @override Base
* @return {Snap}
*/
pluginInitializer: function(xscroll) {
var self = this;
self.xscroll = xscroll.render();
self.snapColIndex = self.userConfig.snapColIndex;
self.snapRowIndex = self.userConfig.snapRowIndex;
self.render();
},
/**
* detroy the plugin
* @memberOf Snap
* @override Base
*/
pluginDestructor: function() {
var self = this;
var xscroll = self.xscroll;
xscroll.on("panend", xscroll._onpanend, xscroll);
xscroll.off("panend", self._snapAnimate, self);
},
/**
* scroll to a col and row with animation
* @memberOf Snap
* @param {number} col col-index
* @param {number} row row-index
* @param {number} duration duration for animation ms
* @param {string} easing easing for animation
* @param {function} callback callback function after animation
* @return {Snap}
*/
snapTo: function(col, row, duration, easing, callback) {
this.snapToCol(col, duration, easing, callback);
this.snapToRow(row, duration, easing, callback);
return this;
},
/**
* scroll to a col with animation
* @memberOf Snap
* @param {number} col col-index
* @param {number} duration duration for animation ms
* @param {string} easing easing for animation
* @param {function} callback callback function after animation
* @return {Snap}
*/
snapToCol: function(col, duration, easing, callback) {
var self = this;
var xscroll = self.xscroll;
var userConfig = self.userConfig;
var duration = duration || userConfig.snapDuration;
var easing = easing || userConfig.snapEasing;
var snapWidth = userConfig.snapWidth;
var snapColsNum = userConfig.snapColsNum;
var snapOffsetLeft = userConfig.snapOffsetLeft;
col = col >= snapColsNum ? snapColsNum - 1 : col < 0 ? 0 : col;
self.prevColIndex = self.snapColIndex;
self.snapColIndex = col;
var left = self.snapColIndex * snapWidth + snapOffsetLeft;
if(left > xscroll.containerWidth - xscroll.boundry.width){
left = xscroll.containerWidth - xscroll.boundry.width;
}
xscroll.scrollLeft(left, duration, easing, callback);
return self;
},
_colChange: function(e) {
var self = this;
if (self.prevColIndex != self.snapColIndex) {
self.trigger('colchange',Util.mix(e,{
type:'colchange',
curColIndex: self.snapColIndex,
prevColIndex: self.prevColIndex
}));
}
return self;
},
/**
* scroll to a row with animation
* @memberOf Snap
* @param {number} row row-index
* @param {number} duration duration for animation ms
* @param {string} easing easing for animation
* @param {function} callback callback function after animation
* @return {Snap}
*/
snapToRow: function(row, duration, easing, callback) {
var self = this;
var xscroll = self.xscroll;
var userConfig = self.userConfig;
var duration = duration || userConfig.snapDuration;
var easing = easing || userConfig.snapEasing;
var snapHeight = userConfig.snapHeight;
var snapRowsNum = userConfig.snapRowsNum;
var snapOffsetTop = userConfig.snapOffsetTop;
row = row >= snapRowsNum ? snapRowsNum - 1 : row < 0 ? 0 : row;
self.prevRowIndex = self.snapRowIndex;
self.snapRowIndex = row;
var top = self.snapRowIndex * snapHeight + snapOffsetTop;
if(top > xscroll.containerHeight - xscroll.boundry.height){
top = xscroll.containerHeight - xscroll.boundry.height;
}
self.xscroll.scrollTop(top, duration, easing,callback);
return self;
},
_rowChange: function(e) {
var self = this;
if (self.prevRowIndex != self.snapRowIndex) {
self.trigger('rowchange', Util.mix(e,{
type:'rowchange',
curRowIndex: self.snapRowIndex,
prevRowIndex: self.prevRowIndex,
}));
}
return self;
},
/*
left => 2;
right => 4;
up => 8;
down => 16;
*/
_snapAnimate: function(e) {
var self = this;
var userConfig = self.userConfig;
var snapWidth = userConfig.snapWidth;
var snapHeight = userConfig.snapHeight;
self.xscroll.__topstart = null;
self.xscroll.__leftstart = null;
var cx = snapWidth / 2;
var cy = snapHeight / 2;
var direction = e.direction;
if (Math.abs(e.velocity) <= 0.2) {
var left = self.xscroll.getScrollLeft();
var top = self.xscroll.getScrollTop();
var snapColIndex = Math.round(left / snapWidth);
var snapRowIndex = Math.round(top / snapHeight);
self.snapTo(snapColIndex, snapRowIndex);
} else if (userConfig.autoStep) {
var transX = self.xscroll.computeScroll("x", e.velocityX);
var transY = self.xscroll.computeScroll("y", e.velocityY);
var snapColIndex = transX && transX.pos ? Math.round(transX.pos / snapWidth) : self.snapColIndex;
var snapRowIndex = transY && transY.pos ? Math.round(transY.pos / snapHeight) : self.snapRowIndex;
var duration = Math.ceil(transX && transX.duration, transY && transY.duration);
if (transX && transX.status == "inside") {
self.snapToCol(snapColIndex, duration, transX && transX.easing, function() {
self.xscroll.boundryCheckX();
});
} else if (transX) {
self.xscroll.scrollLeft(transX.pos, transX.duration, transX.easing, function() {
self.xscroll.boundryCheckX();
self.prevColIndex = self.snapColIndex;
self.snapColIndex = Math.round(Math.abs(self.xscroll.getScrollLeft()) / snapWidth);
});
}
if (transY && transY.status == "inside") {
self.snapToRow(snapRowIndex, duration, transY && transY.easing, function() {
self.xscroll.boundryCheckY();
});
} else if (transY) {
self.xscroll.scrollTop(transY.pos, transY.duration, transY.easing, function() {
self.xscroll.boundryCheckY();
self.prevRowIndex = self.snapRowIndex;
self.snapRowIndex = Math.round(Math.abs(self.xscroll.getScrollTop()) / snapHeight);
});
}
} else {
direction == 2 ? self.snapColIndex++ : direction == 4 ? self.snapColIndex-- : undefined;
direction == 8 ? self.snapRowIndex++ : direction == 16 ? self.snapRowIndex-- : undefined;
self.snapTo(self.snapColIndex, self.snapRowIndex);
}
},
/**
* render snap plugin
* @memberOf Snap
* @return {Snap}
*/
render: function() {
var self = this;
var xscroll = self.xscroll;
self.userConfig.snapWidth = self.userConfig.snapWidth || xscroll.width || 100;
self.userConfig.snapHeight = self.userConfig.snapHeight || xscroll.height || 100;
self.userConfig.snapColsNum = self.userConfig.snapColsNum || Math.max(Math.round(xscroll.containerWidth / xscroll.width), 1);
self.userConfig.snapRowsNum = self.userConfig.snapRowsNum || Math.max(Math.round(xscroll.containerHeight / xscroll.height), 1);
//remove default listener
xscroll.off("panend", xscroll._onpanend);
xscroll.on("panend", self._snapAnimate, self);
self._bindEvt();
return self;
},
_bindEvt:function(){
var self =this;
var xscroll = self.xscroll;
if(self._isEvtBinded) return;
self._isEvtBinded = true;
xscroll.on("scrollend",function(e){
if(e.zoomType == 'y' && !xscroll.isBoundryOutTop() && !xscroll.isBoundryOutBottom()){
self._rowChange(e);
}
})
xscroll.on("scrollend",function(e){
if(e.zoomType == 'x' && !xscroll.isBoundryOutLeft() && !xscroll.isBoundryOutRight()){
self._colChange(e);
}
})
}
});
if (typeof module == 'object' && module.exports) {
module.exports = Snap;
}