UNPKG

2gis-maps

Version:

Interactive 2GIS maps API, based on Leaflet

534 lines (421 loc) 17.3 kB
(function(window, undefined) { 'use strict'; if (!window) return; // Server side var _baron = window.baron, // Stored baron value for noConflict usage $ = window.jQuery, // Trying to use jQuery origin = { v: { // Vertical x: 'Y', pos: 'top', crossPos: 'left', size: 'height', crossSize: 'width', client: 'clientHeight', crossClient: 'clientWidth', offset: 'offsetHeight', crossOffset: 'offsetWidth', offsetPos: 'offsetTop', scroll: 'scrollTop', scrollSize: 'scrollHeight' }, h: { // Horizontal x: 'X', pos: 'left', crossPos: 'top', size: 'width', crossSize: 'height', client: 'clientWidth', crossClient: 'clientHeight', offset: 'offsetWidth', crossOffset: 'offsetHeight', offsetPos: 'offsetLeft', scroll: 'scrollLeft', scrollSize: 'scrollWidth' } }, each = function(obj, iterator) { var i = 0; if (obj.length === undefined || obj === window) obj = [obj]; while (obj[i]) { iterator.call(this, obj[i], i); i++; } }, baron = function(params) { // this - window or jQuery instance var jQueryMode = (this && this[0] && this[0].nodeType), roots, $; params = params || {}; $ = params.$ || window.jQuery; if (jQueryMode) { params.root = roots = this; } else { roots = $(params.root || params.scroller); } return new baron.fn.constructor(roots, params, $); }; baron.fn = { constructor: function(roots, input, $) { var params = validate(input); params.$ = $; each.call(this, roots, function(root, i) { var localParams = clone(params); if (params.root && params.scroller) { localParams.scroller = params.$(params.scroller, root); if (!localParams.scroller.length) { localParams.scroller = root; } } else { localParams.scroller = root; } localParams.root = root; this[i] = init(localParams); this.length = i + 1; }); this.params = params; }, dispose: function() { var params = this.params; each(this, function(item) { item.dispose(params); }); this.params = null; }, update: function() { var i = 0; while (this[i]) { this[i].update.apply(this[i], arguments); i++; } }, baron: function(params) { params.root = []; params.scroller = this.params.scroller; each.call(this, this, function(elem) { params.root.push(elem.root); }); params.direction = (this.params.direction == 'v') ? 'h' : 'v'; params._chain = true; return baron(params); } }; function manageEvents(item, eventManager, mode) { item._eventHandlers = item._eventHandlers || [ // Creating new functions for one baron item only one time { // onScroll: element: item.scroller, handler: function(e) { item.scroll(e); }, type: 'scroll' }, { // onMouseDown: element: item.bar, handler: function(e) { e.preventDefault(); // Text selection disabling in Opera... and all other browsers? item.selection(); // Disable text selection in ie8 item.drag.now = 1; // Save private byte }, type: 'touchstart mousedown' }, { // onMouseUp: element: document, handler: function() { item.selection(1); // Enable text selection item.drag.now = 0; }, type: 'mouseup blur touchend' }, { // onCoordinateReset: element: document, handler: function(e) { if (e.button != 2) { // Not RM item._pos0(e); } }, type: 'touchstart mousedown' }, { // onMouseMove: element: document, handler: function(e) { if (item.drag.now) { item.drag(e); } }, type: 'mousemove touchmove' }, { // onResize: element: window, handler: function() { item.update(); }, type: 'resize' }, { // sizeChange: element: item.root, handler: function() { item.update(); }, type: 'sizeChange' } ]; each(item._eventHandlers, function(event) { if (event.element) { eventManager(event.element, event.type, event.handler, mode); } }); // if (item.scroller) { // event(item.scroller, 'scroll', item._eventHandlers.onScroll, mode); // } // if (item.bar) { // event(item.bar, 'touchstart mousedown', item._eventHandlers.onMouseDown, mode); // } // event(document, 'mouseup blur touchend', item._eventHandlers.onMouseUp, mode); // event(document, 'touchstart mousedown', item._eventHandlers.onCoordinateReset, mode); // event(document, 'mousemove touchmove', item._eventHandlers.onMouseMove, mode); // event(window, 'resize', item._eventHandlers.onResize, mode); // if (item.root) { // event(item.root, 'sizeChange', item._eventHandlers.onResize, mode); // Custon event for alternate baron update mechanism // } } function manageAttr(node, direction, mode) { var attrName = 'data-baron-' + direction; if (mode == 'on') { node.setAttribute(attrName, 'inited'); } else if (mode == 'off') { node.removeAttribute(attrName); } else { return node.getAttribute(attrName); } } function init(params) { if (manageAttr(params.root, params.direction)) return; var out = new item.prototype.constructor(params); // __proto__ of returning object is baron.prototype manageEvents(out, params.event, 'on'); manageAttr(out.root, params.direction, 'on'); out.update(); return out; } function clone(input) { var output = {}; input = input || {}; for (var key in input) { if (input.hasOwnProperty(key)) { output[key] = input[key]; } } return output; } function validate(input) { var output = clone(input); output.direction = output.direction || 'v'; var event = input.event || function(elem, event, func, mode) { output.$(elem)[mode || 'on'](event, func); }; output.event = function(elems, e, func, mode) { each(elems, function(elem) { event(elem, e, func, mode); }); }; return output; } function fire(eventName) { /* jshint validthis:true */ if (this.events && this.events[eventName]) { for (var i = 0 ; i < this.events[eventName].length ; i++) { var args = Array.prototype.slice.call( arguments, 1 ); this.events[eventName][i].apply(this, args); } } } var item = {}; item.prototype = { constructor: function(params) { var $, barPos, scrollerPos0, track, resizePauseTimer, scrollPauseTimer, pause, scrollLastFire, resizeLastFire; resizeLastFire = scrollLastFire = new Date().getTime(); $ = this.$ = params.$; this.event = params.event; this.events = {}; function getNode(sel, context) { return $(sel, context)[0]; // Can be undefined } // DOM elements this.root = params.root; // Always html node, not just selector this.scroller = getNode(params.scroller); // (params.scroller) ? getNode(params.scroller, this.root) : this.root; this.bar = getNode(params.bar, this.root); track = this.track = getNode(params.track, this.root); if (!this.track && this.bar) { track = this.bar.parentNode; } this.clipper = this.scroller.parentNode; // Parameters this.direction = params.direction; this.origin = origin[this.direction]; this.barOnCls = params.barOnCls; this.barTopLimit = 0; pause = params.pause * 1000 || 0; // Updating height or width of bar function setBarSize(size) { /* jshint validthis:true */ var barMinSize = this.barMinSize || 20; if (size > 0 && size < barMinSize) { size = barMinSize; } if (this.bar) { $(this.bar).css(this.origin.size, parseInt(size, 10) + 'px'); } } // Updating top or left bar position function posBar(pos) { /* jshint validthis:true */ if (this.bar) { $(this.bar).css(this.origin.pos, +pos + 'px'); } } // Free path for bar function k() { /* jshint validthis:true */ return track[this.origin.client] - this.barTopLimit - this.bar[this.origin.offset]; } // Relative content top position to bar top position function relToPos(r) { /* jshint validthis:true */ return r * k.call(this) + this.barTopLimit; } // Bar position to relative content position function posToRel(t) { /* jshint validthis:true */ return (t - this.barTopLimit) / k.call(this); } // Cursor position in main direction in px // Now with iOs support this.cursor = function(e) { return e['client' + this.origin.x] || (((e.originalEvent || e).touches || {})[0] || {})['page' + this.origin.x]; }; // Text selection pos preventing function dontPosSelect() { return false; } this.pos = function(x) { // Absolute scroller position in px var ie = 'page' + this.origin.x + 'Offset', key = (this.scroller[ie]) ? ie : this.origin.scroll; if (x !== undefined) this.scroller[key] = x; return this.scroller[key]; }; this.rpos = function(r) { // Relative scroller position (0..1) var free = this.scroller[this.origin.scrollSize] - this.scroller[this.origin.client], x; if (r) x = this.pos(r * free); else x = this.pos(); return x / (free || 1); }; // Switch on the bar by adding user-defined CSS classname to scroller this.barOn = function(dispose) { if (this.barOnCls) { if (dispose || this.scroller[this.origin.client] >= this.scroller[this.origin.scrollSize]) { $(this.root).removeClass(this.barOnCls); } else { $(this.root).addClass(this.barOnCls); } } }; this._pos0 = function(e) { scrollerPos0 = this.cursor(e) - barPos; }; this.drag = function(e) { this.scroller[this.origin.scroll] = posToRel.call(this, this.cursor(e) - scrollerPos0) * (this.scroller[this.origin.scrollSize] - this.scroller[this.origin.client]); }; // Text selection preventing on drag this.selection = function(enable) { this.event(document, 'selectpos selectstart', dontPosSelect, enable ? 'off' : 'on'); }; // onResize & DOM modified handler this.resize = function() { var self = this, delay = 0; if (new Date().getTime() - resizeLastFire < pause) { clearTimeout(resizePauseTimer); delay = pause; } function upd() { var delta = self.scroller[self.origin.crossOffset] - self.scroller[self.origin.crossClient]; if (params.freeze && !self.clipper.style[self.origin.crossSize]) { // Sould fire only once $(self.clipper).css(self.origin.crossSize, self.clipper[self.origin.crossClient] - delta + 'px'); } $(self.scroller).css(self.origin.crossSize, self.clipper[self.origin.crossClient] + delta + 'px'); Array.prototype.unshift.call(arguments, 'resize'); fire.apply(self, arguments); resizeLastFire = new Date().getTime(); } if (delay) { resizePauseTimer = setTimeout(upd, delay); } else { upd(); } }; // onScroll handler this.scroll = function() { var oldBarSize, newBarSize, delay = 0, self = this; if (new Date().getTime() - scrollLastFire < pause) { clearTimeout(scrollPauseTimer); delay = pause; } function upd() { if (self.bar) { newBarSize = (track[self.origin.client] - self.barTopLimit) * self.scroller[self.origin.client] / self.scroller[self.origin.scrollSize]; // Positioning bar if (oldBarSize != newBarSize) { setBarSize.call(self, newBarSize); oldBarSize = newBarSize; } barPos = relToPos.call(self, self.rpos()); posBar.call(self, barPos); } Array.prototype.unshift.call( arguments, 'scroll' ); fire.apply(self, arguments); scrollLastFire = new Date().getTime(); } if (delay) { scrollPauseTimer = setTimeout(upd, delay); } else { upd(); } }; return this; }, update: function(params) { fire.call(this, 'upd', params); // Обновляем параметры всех плагинов this.resize(1); this.barOn(); this.scroll(); return this; }, dispose: function(params) { manageEvents(this, this.event, 'off'); manageAttr(this.root, params.direction, 'off'); $(this.scroller).css(this.origin.crossSize, ''); this.barOn(true); fire.call(this, 'dispose'); }, on: function(eventName, func, arg) { var names = eventName.split(' '); for (var i = 0 ; i < names.length ; i++) { if (names[i] == 'init') { func.call(this, arg); } else { this.events[names[i]] = this.events[names[i]] || []; this.events[names[i]].push(function(userArg) { func.call(this, userArg || arg); }); } } } }; baron.fn.constructor.prototype = baron.fn; item.prototype.constructor.prototype = item.prototype; // Use when you need "baron" global var for another purposes baron.noConflict = function() { window.baron = _baron; // Restoring original value of "baron" global var return baron; }; baron.version = '0.6.6'; if ($ && $.fn) { // Adding baron to jQuery as plugin $.fn.baron = baron; } window.baron = baron; // Use noConflict method if you need window.baron var for another purposes if (window['module'] && module.exports) { module.exports = baron.noConflict(); } })(window);