UNPKG

@zippytech/drag-helper

Version:
221 lines (173 loc) 5.29 kB
/** * Copyright 2015-present Zippy Technologies * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ 'use strict'; var assign = require('object-assign'); var Region = require('@zippytech/region-align'); var hasTouch = require('@zippytech/has-touch'); var once = require('./utils/once'); var mobileTest = global.navigator ? /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test( global.navigator.userAgent ) : false; var isMobile = hasTouch && mobileTest; var Helper = function(config) { this.config = config; }; var EVENTS = { move: isMobile ? 'touchmove' : 'mousemove', up: isMobile ? 'touchend' : 'mouseup' }; function emptyFn() {} function getPageCoords(event) { var firstTouch; var pageX = event.pageX; var pageY = event.pageY; if (isMobile && event.touches && (firstTouch = event.touches[0])) { pageX = firstTouch.pageX; pageY = firstTouch.pageY; } return { pageX: pageX, pageY: pageY }; } assign(Helper.prototype, { /** * Should be called on a mousedown event * * @param {Event} event * @return {[type]} [description] */ initDrag: function(event) { this.onDragInit(event); var events = this.config.events || EVENTS; var onDragStart = once(this.onDragStart, this); var target = isMobile ? event.target : global; var mouseUpListener = (function(event) { this.onDrop(event); target.removeEventListener(events.move, mouseMoveListener); target.removeEventListener(events.up, mouseUpListener); }).bind(this); var mouseMoveListener = (function(event) { /** * Make sure the left mouse button is pressed */ if (!isMobile && event.which !== 1) { mouseUpListener(event); return; } onDragStart(event); this.onDrag(event); }).bind(this); target.addEventListener(events.move, mouseMoveListener, false); target.addEventListener(events.up, mouseUpListener); }, onDragInit: function(event) { var config = { diff: { left: 0, top: 0 } }; this.state = { config: config }; if (this.config.region) { this.state.initialRegion = Region.from(this.config.region); this.state.dragRegion = (config.dragRegion = this.state.initialRegion.clone()); } if (this.config.constrainTo) { this.state.constrainTo = Region.from(this.config.constrainTo); } this.callConfig('onDragInit', event); }, /** * Called when the first mousemove event occurs after drag is initialized * @param {Event} event */ onDragStart: function(event) { this.state.initPageCoords = getPageCoords(event); this.state.didDrag = (this.state.config.didDrag = true); this.callConfig('onDragStart', event); }, /** * Called on all mousemove events after drag is initialized. * * @param {Event} event */ onDrag: function(event) { var config = this.state.config; var initPageCoords = this.state.initPageCoords; var eventCoords = getPageCoords(event); var diff = (config.diff = { left: eventCoords.pageX - initPageCoords.pageX, top: eventCoords.pageY - initPageCoords.pageY }); if (this.state.initialRegion) { var dragRegion = config.dragRegion; //set the dragRegion to initial coords dragRegion.set(this.state.initialRegion); //shift it to the new position dragRegion.shift(diff); if (this.state.constrainTo) { //and finally constrain it if it's the case var boolConstrained = dragRegion.constrainTo(this.state.constrainTo); diff.left = dragRegion.left - this.state.initialRegion.left; diff.top = dragRegion.top - this.state.initialRegion.top; // console.log(diff); } config.dragRegion = dragRegion; } this.callConfig('onDrag', event); }, /** * Called on the mouseup event on window * * @param {Event} event */ onDrop: function(event) { this.callConfig('onDrop', event); this.state = null; }, callConfig: function(fnName, event) { var config = this.state.config; var args = [event, config]; var fn = this.config[fnName]; if (fn) { fn.apply(this, args); } } }); module.exports = function(event, config) { if (config.scope) { var skippedKeys = { scope: 1, region: 1, constrainTo: 1 }; Object.keys(config).forEach(function(key) { var value = config[key]; if (key in skippedKeys) { return; } if (typeof value == 'function') { config[key] = value.bind(config.scope); } }); } var helper = new Helper(config); helper.initDrag(event); return helper; };