[{"description":"Creates a popup component","tags":[{"title":"class","description":null,"type":null,"name":"Popup"},{"title":"param","description":null,"type":{"type":"NameExpression","name":"Object"},"name":"options"},{"title":"param","description":null,"type":{"type":"NameExpression","name":"Boolean"},"name":"options.closeButton"},{"title":"param","description":null,"type":{"type":"NameExpression","name":"Boolean"},"name":"options.closeOnClick"},{"title":"example","description":"var tooltip = new mapboxgl.Popup()\n  .setLatLng(map.unproject(e.point))\n  .setHTML(\"<h1>Hello World!</h1>\")\n  .addTo(map);"},{"title":"name","name":"Popup"},{"title":"kind","kind":"class"}],"context":{"loc":{"start":{"line":22,"column":0},"end":{"line":28,"column":1}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/popup.js","code":"'use strict';\n\nmodule.exports = Popup;\n\nvar util = require('../util/util');\nvar Evented = require('../util/evented');\nvar DOM = require('../util/dom');\nvar LatLng = require('../geo/lat_lng');\n\n/**\n * Creates a popup component\n * @class Popup\n * @param {Object} options\n * @param {Boolean} options.closeButton\n * @param {Boolean} options.closeOnClick\n * @example\n * var tooltip = new mapboxgl.Popup()\n *   .setLatLng(map.unproject(e.point))\n *   .setHTML(\"<h1>Hello World!</h1>\")\n *   .addTo(map);\n */\nfunction Popup(options) {\n    util.setOptions(this, options);\n    util.bindAll([\n        '_updatePosition',\n        '_onClickClose'],\n        this);\n}\n\nPopup.prototype = util.inherit(Evented, /** @lends Popup.prototype */{\n    options: {\n        closeButton: true,\n        closeOnClick: true\n    },\n\n    /**\n     * Attaches the popup to a map\n     * @param {Map} map\n     * @returns {Popup} `this`\n     */\n    addTo: function(map) {\n        this._map = map;\n        this._map.on('move', this._updatePosition);\n        if (this.options.closeOnClick) {\n            this._map.on('click', this._onClickClose);\n        }\n        this._update();\n        return this;\n    },\n\n    /**\n     * Removes the popup from the map\n     * @example\n     * var popup = new mapboxgl.Popup().addTo(map);\n     * popup.remove();\n     * @returns {Popup} `this`\n     */\n    remove: function() {\n        if (this._container) {\n            this._container.parentNode.removeChild(this._container);\n        }\n\n        if (this._map) {\n            this._map.off('move', this._updatePosition);\n            this._map.off('click', this._onClickClose);\n            delete this._map;\n        }\n\n        return this;\n    },\n\n    /**\n     * Get the current coordinates of popup element relative to map\n     * @returns {LatLng}\n     */\n    getLatLng: function() {\n        return this._latLng;\n    },\n\n    /**\n     * Set the coordinates of a popup element to a map\n     * @param {LatLng} latlng\n     * @returns {Popup} `this`\n     */\n    setLatLng: function(latlng) {\n        this._latLng = LatLng.convert(latlng);\n        this._update();\n        return this;\n    },\n\n    /**\n     * Popuplate a popup element with text only content\n     * @param {string} text\n     * @returns {Popup} `this`\n     */\n    setText: function(text) {\n        this._content = document.createTextNode(text);\n        this._updateContent();\n        return this;\n    },\n\n    /**\n     * Popuplate a popup element with HTML content\n     * @param {string} html\n     * @returns {Popup} `this`\n     */\n    setHTML: function(html) {\n        this._content = document.createDocumentFragment();\n\n        var temp = document.createElement('body'), child;\n        temp.innerHTML = html;\n        while (true) {\n            child = temp.firstChild;\n            if (!child) break;\n            this._content.appendChild(child);\n        }\n\n        this._updateContent();\n        return this;\n    },\n\n    _update: function() {\n        if (!this._map) { return; }\n\n        if (!this._container) {\n            this._container = DOM.create('div', 'mapboxgl-popup', this._map.getContainer());\n\n            this._tip     = DOM.create('div', 'mapboxgl-popup-tip',     this._container);\n            this._wrapper = DOM.create('div', 'mapboxgl-popup-content', this._container);\n\n            if (this.options.closeButton) {\n                this._closeButton = DOM.create('button', 'mapboxgl-popup-close-button', this._wrapper);\n                this._closeButton.innerHTML = '&#215;';\n                this._closeButton.addEventListener('click', this._onClickClose);\n            }\n        }\n\n        this._updateContent();\n        this._updatePosition();\n    },\n\n    _updateContent: function() {\n        if (!this._content || !this._container) { return; }\n\n        var node = this._wrapper;\n\n        while (node.hasChildNodes()) {\n            node.removeChild(node.firstChild);\n        }\n\n        node.appendChild(this._closeButton);\n        node.appendChild(this._content);\n    },\n\n    _updatePosition: function() {\n        if (!this._latLng || !this._container) { return; }\n\n        var pos = this._map.project(this._latLng).round(),\n            anchor = this.options.anchor;\n\n        if (!anchor) {\n            var width = this._container.offsetWidth,\n                height = this._container.offsetHeight;\n\n            if (pos.y < height) {\n                anchor = ['top'];\n            } else if (pos.y > this._map.transform.height - height) {\n                anchor = ['bottom'];\n            } else {\n                anchor = [];\n            }\n\n            if (pos.x < width / 2) {\n                anchor.push('left');\n            } else if (pos.x > this._map.transform.width - width / 2) {\n                anchor.push('right');\n            }\n\n            if (anchor.length === 0) {\n                anchor = 'bottom';\n            } else {\n                anchor = anchor.join('-');\n            }\n\n            this.options.anchor = anchor;\n        }\n\n        var anchorTranslate = {\n            'top': 'translate(-50%,0)',\n            'top-left': 'translate(0,0)',\n            'top-right': 'translate(-100%,0)',\n            'bottom': 'translate(-50%,-100%)',\n            'bottom-left': 'translate(0,-100%)',\n            'bottom-right': 'translate(-100%,-100%)',\n            'left': 'translate(0,-50%)',\n            'right': 'translate(-100%,-50%)'\n        };\n\n        var classList = this._container.classList;\n        for (var key in anchorTranslate) {\n            classList.remove('mapboxgl-popup-anchor-' + key);\n        }\n        classList.add('mapboxgl-popup-anchor-' + anchor);\n\n        DOM.setTransform(this._container, anchorTranslate[anchor] + ' translate(' + pos.x + 'px,' + pos.y + 'px)');\n    },\n\n    _onClickClose: function() {\n        this.remove();\n    }\n});","path":"js/ui/popup.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/popup.js#L22-L28"},"params":[{"title":"param","description":null,"type":{"type":"NameExpression","name":"Object"},"name":"options"},{"title":"param","description":null,"type":{"type":"NameExpression","name":"Boolean"},"name":"options.closeButton"},{"title":"param","description":null,"type":{"type":"NameExpression","name":"Boolean"},"name":"options.closeOnClick"}],"examples":["<span class=\"hljs-keyword\">var</span> tooltip = <span class=\"hljs-keyword\">new</span> mapboxgl.Popup()\n  .setLatLng(map.unproject(e.point))\n  .setHTML(<span class=\"hljs-string\">\"&lt;h1&gt;Hello World!&lt;/h1&gt;\"</span>)\n  .addTo(map);"],"name":"Popup","kind":"class","members":{"instance":[{"description":"Popuplate a popup element with text only content","tags":[{"title":"param","description":null,"type":{"type":"NameExpression","name":"string"},"name":"text"},{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Popup"}},{"title":"name","name":"setText"},{"title":"memberof","description":"Popup"},{"title":"instance"}],"context":{"loc":{"start":{"line":96,"column":4},"end":{"line":100,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/popup.js","code":"{\n    options: {\n        closeButton: true,\n        closeOnClick: true\n    },\n\n    /**\n     * Attaches the popup to a map\n     * @param {Map} map\n     * @returns {Popup} `this`\n     */\n    addTo: function(map) {\n        this._map = map;\n        this._map.on('move', this._updatePosition);\n        if (this.options.closeOnClick) {\n            this._map.on('click', this._onClickClose);\n        }\n        this._update();\n        return this;\n    },\n\n    /**\n     * Removes the popup from the map\n     * @example\n     * var popup = new mapboxgl.Popup().addTo(map);\n     * popup.remove();\n     * @returns {Popup} `this`\n     */\n    remove: function() {\n        if (this._container) {\n            this._container.parentNode.removeChild(this._container);\n        }\n\n        if (this._map) {\n            this._map.off('move', this._updatePosition);\n            this._map.off('click', this._onClickClose);\n            delete this._map;\n        }\n\n        return this;\n    },\n\n    /**\n     * Get the current coordinates of popup element relative to map\n     * @returns {LatLng}\n     */\n    getLatLng: function() {\n        return this._latLng;\n    },\n\n    /**\n     * Set the coordinates of a popup element to a map\n     * @param {LatLng} latlng\n     * @returns {Popup} `this`\n     */\n    setLatLng: function(latlng) {\n        this._latLng = LatLng.convert(latlng);\n        this._update();\n        return this;\n    },\n\n    /**\n     * Popuplate a popup element with text only content\n     * @param {string} text\n     * @returns {Popup} `this`\n     */\n    setText: function(text) {\n        this._content = document.createTextNode(text);\n        this._updateContent();\n        return this;\n    },\n\n    /**\n     * Popuplate a popup element with HTML content\n     * @param {string} html\n     * @returns {Popup} `this`\n     */\n    setHTML: function(html) {\n        this._content = document.createDocumentFragment();\n\n        var temp = document.createElement('body'), child;\n        temp.innerHTML = html;\n        while (true) {\n            child = temp.firstChild;\n            if (!child) break;\n            this._content.appendChild(child);\n        }\n\n        this._updateContent();\n        return this;\n    },\n\n    _update: function() {\n        if (!this._map) { return; }\n\n        if (!this._container) {\n            this._container = DOM.create('div', 'mapboxgl-popup', this._map.getContainer());\n\n            this._tip     = DOM.create('div', 'mapboxgl-popup-tip',     this._container);\n            this._wrapper = DOM.create('div', 'mapboxgl-popup-content', this._container);\n\n            if (this.options.closeButton) {\n                this._closeButton = DOM.create('button', 'mapboxgl-popup-close-button', this._wrapper);\n                this._closeButton.innerHTML = '&#215;';\n                this._closeButton.addEventListener('click', this._onClickClose);\n            }\n        }\n\n        this._updateContent();\n        this._updatePosition();\n    },\n\n    _updateContent: function() {\n        if (!this._content || !this._container) { return; }\n\n        var node = this._wrapper;\n\n        while (node.hasChildNodes()) {\n            node.removeChild(node.firstChild);\n        }\n\n        node.appendChild(this._closeButton);\n        node.appendChild(this._content);\n    },\n\n    _updatePosition: function() {\n        if (!this._latLng || !this._container) { return; }\n\n        var pos = this._map.project(this._latLng).round(),\n            anchor = this.options.anchor;\n\n        if (!anchor) {\n            var width = this._container.offsetWidth,\n                height = this._container.offsetHeight;\n\n            if (pos.y < height) {\n                anchor = ['top'];\n            } else if (pos.y > this._map.transform.height - height) {\n                anchor = ['bottom'];\n            } else {\n                anchor = [];\n            }\n\n            if (pos.x < width / 2) {\n                anchor.push('left');\n            } else if (pos.x > this._map.transform.width - width / 2) {\n                anchor.push('right');\n            }\n\n            if (anchor.length === 0) {\n                anchor = 'bottom';\n            } else {\n                anchor = anchor.join('-');\n            }\n\n            this.options.anchor = anchor;\n        }\n\n        var anchorTranslate = {\n            'top': 'translate(-50%,0)',\n            'top-left': 'translate(0,0)',\n            'top-right': 'translate(-100%,0)',\n            'bottom': 'translate(-50%,-100%)',\n            'bottom-left': 'translate(0,-100%)',\n            'bottom-right': 'translate(-100%,-100%)',\n            'left': 'translate(0,-50%)',\n            'right': 'translate(-100%,-50%)'\n        };\n\n        var classList = this._container.classList;\n        for (var key in anchorTranslate) {\n            classList.remove('mapboxgl-popup-anchor-' + key);\n        }\n        classList.add('mapboxgl-popup-anchor-' + anchor);\n\n        DOM.setTransform(this._container, anchorTranslate[anchor] + ' translate(' + pos.x + 'px,' + pos.y + 'px)');\n    },\n\n    _onClickClose: function() {\n        this.remove();\n    }\n}","path":"js/ui/popup.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/popup.js#L96-L100"},"params":[{"title":"param","description":null,"type":{"type":"NameExpression","name":"string"},"name":"text"}],"returns":[{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Popup"}}],"name":"setText","memberof":"Popup","scope":"instance","members":{"instance":[],"static":[]},"path":["Popup","setText"]},{"description":"Popuplate a popup element with HTML content","tags":[{"title":"param","description":null,"type":{"type":"NameExpression","name":"string"},"name":"html"},{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Popup"}},{"title":"name","name":"setHTML"},{"title":"memberof","description":"Popup"},{"title":"instance"}],"context":{"loc":{"start":{"line":107,"column":4},"end":{"line":120,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/popup.js","code":"{\n    options: {\n        closeButton: true,\n        closeOnClick: true\n    },\n\n    /**\n     * Attaches the popup to a map\n     * @param {Map} map\n     * @returns {Popup} `this`\n     */\n    addTo: function(map) {\n        this._map = map;\n        this._map.on('move', this._updatePosition);\n        if (this.options.closeOnClick) {\n            this._map.on('click', this._onClickClose);\n        }\n        this._update();\n        return this;\n    },\n\n    /**\n     * Removes the popup from the map\n     * @example\n     * var popup = new mapboxgl.Popup().addTo(map);\n     * popup.remove();\n     * @returns {Popup} `this`\n     */\n    remove: function() {\n        if (this._container) {\n            this._container.parentNode.removeChild(this._container);\n        }\n\n        if (this._map) {\n            this._map.off('move', this._updatePosition);\n            this._map.off('click', this._onClickClose);\n            delete this._map;\n        }\n\n        return this;\n    },\n\n    /**\n     * Get the current coordinates of popup element relative to map\n     * @returns {LatLng}\n     */\n    getLatLng: function() {\n        return this._latLng;\n    },\n\n    /**\n     * Set the coordinates of a popup element to a map\n     * @param {LatLng} latlng\n     * @returns {Popup} `this`\n     */\n    setLatLng: function(latlng) {\n        this._latLng = LatLng.convert(latlng);\n        this._update();\n        return this;\n    },\n\n    /**\n     * Popuplate a popup element with text only content\n     * @param {string} text\n     * @returns {Popup} `this`\n     */\n    setText: function(text) {\n        this._content = document.createTextNode(text);\n        this._updateContent();\n        return this;\n    },\n\n    /**\n     * Popuplate a popup element with HTML content\n     * @param {string} html\n     * @returns {Popup} `this`\n     */\n    setHTML: function(html) {\n        this._content = document.createDocumentFragment();\n\n        var temp = document.createElement('body'), child;\n        temp.innerHTML = html;\n        while (true) {\n            child = temp.firstChild;\n            if (!child) break;\n            this._content.appendChild(child);\n        }\n\n        this._updateContent();\n        return this;\n    },\n\n    _update: function() {\n        if (!this._map) { return; }\n\n        if (!this._container) {\n            this._container = DOM.create('div', 'mapboxgl-popup', this._map.getContainer());\n\n            this._tip     = DOM.create('div', 'mapboxgl-popup-tip',     this._container);\n            this._wrapper = DOM.create('div', 'mapboxgl-popup-content', this._container);\n\n            if (this.options.closeButton) {\n                this._closeButton = DOM.create('button', 'mapboxgl-popup-close-button', this._wrapper);\n                this._closeButton.innerHTML = '&#215;';\n                this._closeButton.addEventListener('click', this._onClickClose);\n            }\n        }\n\n        this._updateContent();\n        this._updatePosition();\n    },\n\n    _updateContent: function() {\n        if (!this._content || !this._container) { return; }\n\n        var node = this._wrapper;\n\n        while (node.hasChildNodes()) {\n            node.removeChild(node.firstChild);\n        }\n\n        node.appendChild(this._closeButton);\n        node.appendChild(this._content);\n    },\n\n    _updatePosition: function() {\n        if (!this._latLng || !this._container) { return; }\n\n        var pos = this._map.project(this._latLng).round(),\n            anchor = this.options.anchor;\n\n        if (!anchor) {\n            var width = this._container.offsetWidth,\n                height = this._container.offsetHeight;\n\n            if (pos.y < height) {\n                anchor = ['top'];\n            } else if (pos.y > this._map.transform.height - height) {\n                anchor = ['bottom'];\n            } else {\n                anchor = [];\n            }\n\n            if (pos.x < width / 2) {\n                anchor.push('left');\n            } else if (pos.x > this._map.transform.width - width / 2) {\n                anchor.push('right');\n            }\n\n            if (anchor.length === 0) {\n                anchor = 'bottom';\n            } else {\n                anchor = anchor.join('-');\n            }\n\n            this.options.anchor = anchor;\n        }\n\n        var anchorTranslate = {\n            'top': 'translate(-50%,0)',\n            'top-left': 'translate(0,0)',\n            'top-right': 'translate(-100%,0)',\n            'bottom': 'translate(-50%,-100%)',\n            'bottom-left': 'translate(0,-100%)',\n            'bottom-right': 'translate(-100%,-100%)',\n            'left': 'translate(0,-50%)',\n            'right': 'translate(-100%,-50%)'\n        };\n\n        var classList = this._container.classList;\n        for (var key in anchorTranslate) {\n            classList.remove('mapboxgl-popup-anchor-' + key);\n        }\n        classList.add('mapboxgl-popup-anchor-' + anchor);\n\n        DOM.setTransform(this._container, anchorTranslate[anchor] + ' translate(' + pos.x + 'px,' + pos.y + 'px)');\n    },\n\n    _onClickClose: function() {\n        this.remove();\n    }\n}","path":"js/ui/popup.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/popup.js#L107-L120"},"params":[{"title":"param","description":null,"type":{"type":"NameExpression","name":"string"},"name":"html"}],"returns":[{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Popup"}}],"name":"setHTML","memberof":"Popup","scope":"instance","members":{"instance":[],"static":[]},"path":["Popup","setHTML"]},{"description":"Set the coordinates of a popup element to a map","tags":[{"title":"param","description":null,"type":{"type":"NameExpression","name":"LatLng"},"name":"latlng"},{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Popup"}},{"title":"name","name":"setLatLng"},{"title":"memberof","description":"Popup"},{"title":"instance"}],"context":{"loc":{"start":{"line":85,"column":4},"end":{"line":89,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/popup.js","code":"{\n    options: {\n        closeButton: true,\n        closeOnClick: true\n    },\n\n    /**\n     * Attaches the popup to a map\n     * @param {Map} map\n     * @returns {Popup} `this`\n     */\n    addTo: function(map) {\n        this._map = map;\n        this._map.on('move', this._updatePosition);\n        if (this.options.closeOnClick) {\n            this._map.on('click', this._onClickClose);\n        }\n        this._update();\n        return this;\n    },\n\n    /**\n     * Removes the popup from the map\n     * @example\n     * var popup = new mapboxgl.Popup().addTo(map);\n     * popup.remove();\n     * @returns {Popup} `this`\n     */\n    remove: function() {\n        if (this._container) {\n            this._container.parentNode.removeChild(this._container);\n        }\n\n        if (this._map) {\n            this._map.off('move', this._updatePosition);\n            this._map.off('click', this._onClickClose);\n            delete this._map;\n        }\n\n        return this;\n    },\n\n    /**\n     * Get the current coordinates of popup element relative to map\n     * @returns {LatLng}\n     */\n    getLatLng: function() {\n        return this._latLng;\n    },\n\n    /**\n     * Set the coordinates of a popup element to a map\n     * @param {LatLng} latlng\n     * @returns {Popup} `this`\n     */\n    setLatLng: function(latlng) {\n        this._latLng = LatLng.convert(latlng);\n        this._update();\n        return this;\n    },\n\n    /**\n     * Popuplate a popup element with text only content\n     * @param {string} text\n     * @returns {Popup} `this`\n     */\n    setText: function(text) {\n        this._content = document.createTextNode(text);\n        this._updateContent();\n        return this;\n    },\n\n    /**\n     * Popuplate a popup element with HTML content\n     * @param {string} html\n     * @returns {Popup} `this`\n     */\n    setHTML: function(html) {\n        this._content = document.createDocumentFragment();\n\n        var temp = document.createElement('body'), child;\n        temp.innerHTML = html;\n        while (true) {\n            child = temp.firstChild;\n            if (!child) break;\n            this._content.appendChild(child);\n        }\n\n        this._updateContent();\n        return this;\n    },\n\n    _update: function() {\n        if (!this._map) { return; }\n\n        if (!this._container) {\n            this._container = DOM.create('div', 'mapboxgl-popup', this._map.getContainer());\n\n            this._tip     = DOM.create('div', 'mapboxgl-popup-tip',     this._container);\n            this._wrapper = DOM.create('div', 'mapboxgl-popup-content', this._container);\n\n            if (this.options.closeButton) {\n                this._closeButton = DOM.create('button', 'mapboxgl-popup-close-button', this._wrapper);\n                this._closeButton.innerHTML = '&#215;';\n                this._closeButton.addEventListener('click', this._onClickClose);\n            }\n        }\n\n        this._updateContent();\n        this._updatePosition();\n    },\n\n    _updateContent: function() {\n        if (!this._content || !this._container) { return; }\n\n        var node = this._wrapper;\n\n        while (node.hasChildNodes()) {\n            node.removeChild(node.firstChild);\n        }\n\n        node.appendChild(this._closeButton);\n        node.appendChild(this._content);\n    },\n\n    _updatePosition: function() {\n        if (!this._latLng || !this._container) { return; }\n\n        var pos = this._map.project(this._latLng).round(),\n            anchor = this.options.anchor;\n\n        if (!anchor) {\n            var width = this._container.offsetWidth,\n                height = this._container.offsetHeight;\n\n            if (pos.y < height) {\n                anchor = ['top'];\n            } else if (pos.y > this._map.transform.height - height) {\n                anchor = ['bottom'];\n            } else {\n                anchor = [];\n            }\n\n            if (pos.x < width / 2) {\n                anchor.push('left');\n            } else if (pos.x > this._map.transform.width - width / 2) {\n                anchor.push('right');\n            }\n\n            if (anchor.length === 0) {\n                anchor = 'bottom';\n            } else {\n                anchor = anchor.join('-');\n            }\n\n            this.options.anchor = anchor;\n        }\n\n        var anchorTranslate = {\n            'top': 'translate(-50%,0)',\n            'top-left': 'translate(0,0)',\n            'top-right': 'translate(-100%,0)',\n            'bottom': 'translate(-50%,-100%)',\n            'bottom-left': 'translate(0,-100%)',\n            'bottom-right': 'translate(-100%,-100%)',\n            'left': 'translate(0,-50%)',\n            'right': 'translate(-100%,-50%)'\n        };\n\n        var classList = this._container.classList;\n        for (var key in anchorTranslate) {\n            classList.remove('mapboxgl-popup-anchor-' + key);\n        }\n        classList.add('mapboxgl-popup-anchor-' + anchor);\n\n        DOM.setTransform(this._container, anchorTranslate[anchor] + ' translate(' + pos.x + 'px,' + pos.y + 'px)');\n    },\n\n    _onClickClose: function() {\n        this.remove();\n    }\n}","path":"js/ui/popup.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/popup.js#L85-L89"},"params":[{"title":"param","description":null,"type":{"type":"NameExpression","name":"LatLng"},"name":"latlng"}],"returns":[{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Popup"}}],"name":"setLatLng","memberof":"Popup","scope":"instance","members":{"instance":[],"static":[]},"path":["Popup","setLatLng"]},{"description":"Removes the popup from the map","tags":[{"title":"example","description":"var popup = new mapboxgl.Popup().addTo(map);\npopup.remove();"},{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Popup"}},{"title":"name","name":"remove"},{"title":"memberof","description":"Popup"},{"title":"instance"}],"context":{"loc":{"start":{"line":58,"column":4},"end":{"line":70,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/popup.js","code":"{\n    options: {\n        closeButton: true,\n        closeOnClick: true\n    },\n\n    /**\n     * Attaches the popup to a map\n     * @param {Map} map\n     * @returns {Popup} `this`\n     */\n    addTo: function(map) {\n        this._map = map;\n        this._map.on('move', this._updatePosition);\n        if (this.options.closeOnClick) {\n            this._map.on('click', this._onClickClose);\n        }\n        this._update();\n        return this;\n    },\n\n    /**\n     * Removes the popup from the map\n     * @example\n     * var popup = new mapboxgl.Popup().addTo(map);\n     * popup.remove();\n     * @returns {Popup} `this`\n     */\n    remove: function() {\n        if (this._container) {\n            this._container.parentNode.removeChild(this._container);\n        }\n\n        if (this._map) {\n            this._map.off('move', this._updatePosition);\n            this._map.off('click', this._onClickClose);\n            delete this._map;\n        }\n\n        return this;\n    },\n\n    /**\n     * Get the current coordinates of popup element relative to map\n     * @returns {LatLng}\n     */\n    getLatLng: function() {\n        return this._latLng;\n    },\n\n    /**\n     * Set the coordinates of a popup element to a map\n     * @param {LatLng} latlng\n     * @returns {Popup} `this`\n     */\n    setLatLng: function(latlng) {\n        this._latLng = LatLng.convert(latlng);\n        this._update();\n        return this;\n    },\n\n    /**\n     * Popuplate a popup element with text only content\n     * @param {string} text\n     * @returns {Popup} `this`\n     */\n    setText: function(text) {\n        this._content = document.createTextNode(text);\n        this._updateContent();\n        return this;\n    },\n\n    /**\n     * Popuplate a popup element with HTML content\n     * @param {string} html\n     * @returns {Popup} `this`\n     */\n    setHTML: function(html) {\n        this._content = document.createDocumentFragment();\n\n        var temp = document.createElement('body'), child;\n        temp.innerHTML = html;\n        while (true) {\n            child = temp.firstChild;\n            if (!child) break;\n            this._content.appendChild(child);\n        }\n\n        this._updateContent();\n        return this;\n    },\n\n    _update: function() {\n        if (!this._map) { return; }\n\n        if (!this._container) {\n            this._container = DOM.create('div', 'mapboxgl-popup', this._map.getContainer());\n\n            this._tip     = DOM.create('div', 'mapboxgl-popup-tip',     this._container);\n            this._wrapper = DOM.create('div', 'mapboxgl-popup-content', this._container);\n\n            if (this.options.closeButton) {\n                this._closeButton = DOM.create('button', 'mapboxgl-popup-close-button', this._wrapper);\n                this._closeButton.innerHTML = '&#215;';\n                this._closeButton.addEventListener('click', this._onClickClose);\n            }\n        }\n\n        this._updateContent();\n        this._updatePosition();\n    },\n\n    _updateContent: function() {\n        if (!this._content || !this._container) { return; }\n\n        var node = this._wrapper;\n\n        while (node.hasChildNodes()) {\n            node.removeChild(node.firstChild);\n        }\n\n        node.appendChild(this._closeButton);\n        node.appendChild(this._content);\n    },\n\n    _updatePosition: function() {\n        if (!this._latLng || !this._container) { return; }\n\n        var pos = this._map.project(this._latLng).round(),\n            anchor = this.options.anchor;\n\n        if (!anchor) {\n            var width = this._container.offsetWidth,\n                height = this._container.offsetHeight;\n\n            if (pos.y < height) {\n                anchor = ['top'];\n            } else if (pos.y > this._map.transform.height - height) {\n                anchor = ['bottom'];\n            } else {\n                anchor = [];\n            }\n\n            if (pos.x < width / 2) {\n                anchor.push('left');\n            } else if (pos.x > this._map.transform.width - width / 2) {\n                anchor.push('right');\n            }\n\n            if (anchor.length === 0) {\n                anchor = 'bottom';\n            } else {\n                anchor = anchor.join('-');\n            }\n\n            this.options.anchor = anchor;\n        }\n\n        var anchorTranslate = {\n            'top': 'translate(-50%,0)',\n            'top-left': 'translate(0,0)',\n            'top-right': 'translate(-100%,0)',\n            'bottom': 'translate(-50%,-100%)',\n            'bottom-left': 'translate(0,-100%)',\n            'bottom-right': 'translate(-100%,-100%)',\n            'left': 'translate(0,-50%)',\n            'right': 'translate(-100%,-50%)'\n        };\n\n        var classList = this._container.classList;\n        for (var key in anchorTranslate) {\n            classList.remove('mapboxgl-popup-anchor-' + key);\n        }\n        classList.add('mapboxgl-popup-anchor-' + anchor);\n\n        DOM.setTransform(this._container, anchorTranslate[anchor] + ' translate(' + pos.x + 'px,' + pos.y + 'px)');\n    },\n\n    _onClickClose: function() {\n        this.remove();\n    }\n}","path":"js/ui/popup.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/popup.js#L58-L70"},"examples":["<span class=\"hljs-keyword\">var</span> popup = <span class=\"hljs-keyword\">new</span> mapboxgl.Popup().addTo(map);\npopup.remove();"],"returns":[{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Popup"}}],"name":"remove","memberof":"Popup","scope":"instance","members":{"instance":[],"static":[]},"path":["Popup","remove"]},{"description":"Get the current coordinates of popup element relative to map","tags":[{"title":"returns","description":null,"type":{"type":"NameExpression","name":"LatLng"}},{"title":"name","name":"getLatLng"},{"title":"memberof","description":"Popup"},{"title":"instance"}],"context":{"loc":{"start":{"line":76,"column":4},"end":{"line":78,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/popup.js","code":"{\n    options: {\n        closeButton: true,\n        closeOnClick: true\n    },\n\n    /**\n     * Attaches the popup to a map\n     * @param {Map} map\n     * @returns {Popup} `this`\n     */\n    addTo: function(map) {\n        this._map = map;\n        this._map.on('move', this._updatePosition);\n        if (this.options.closeOnClick) {\n            this._map.on('click', this._onClickClose);\n        }\n        this._update();\n        return this;\n    },\n\n    /**\n     * Removes the popup from the map\n     * @example\n     * var popup = new mapboxgl.Popup().addTo(map);\n     * popup.remove();\n     * @returns {Popup} `this`\n     */\n    remove: function() {\n        if (this._container) {\n            this._container.parentNode.removeChild(this._container);\n        }\n\n        if (this._map) {\n            this._map.off('move', this._updatePosition);\n            this._map.off('click', this._onClickClose);\n            delete this._map;\n        }\n\n        return this;\n    },\n\n    /**\n     * Get the current coordinates of popup element relative to map\n     * @returns {LatLng}\n     */\n    getLatLng: function() {\n        return this._latLng;\n    },\n\n    /**\n     * Set the coordinates of a popup element to a map\n     * @param {LatLng} latlng\n     * @returns {Popup} `this`\n     */\n    setLatLng: function(latlng) {\n        this._latLng = LatLng.convert(latlng);\n        this._update();\n        return this;\n    },\n\n    /**\n     * Popuplate a popup element with text only content\n     * @param {string} text\n     * @returns {Popup} `this`\n     */\n    setText: function(text) {\n        this._content = document.createTextNode(text);\n        this._updateContent();\n        return this;\n    },\n\n    /**\n     * Popuplate a popup element with HTML content\n     * @param {string} html\n     * @returns {Popup} `this`\n     */\n    setHTML: function(html) {\n        this._content = document.createDocumentFragment();\n\n        var temp = document.createElement('body'), child;\n        temp.innerHTML = html;\n        while (true) {\n            child = temp.firstChild;\n            if (!child) break;\n            this._content.appendChild(child);\n        }\n\n        this._updateContent();\n        return this;\n    },\n\n    _update: function() {\n        if (!this._map) { return; }\n\n        if (!this._container) {\n            this._container = DOM.create('div', 'mapboxgl-popup', this._map.getContainer());\n\n            this._tip     = DOM.create('div', 'mapboxgl-popup-tip',     this._container);\n            this._wrapper = DOM.create('div', 'mapboxgl-popup-content', this._container);\n\n            if (this.options.closeButton) {\n                this._closeButton = DOM.create('button', 'mapboxgl-popup-close-button', this._wrapper);\n                this._closeButton.innerHTML = '&#215;';\n                this._closeButton.addEventListener('click', this._onClickClose);\n            }\n        }\n\n        this._updateContent();\n        this._updatePosition();\n    },\n\n    _updateContent: function() {\n        if (!this._content || !this._container) { return; }\n\n        var node = this._wrapper;\n\n        while (node.hasChildNodes()) {\n            node.removeChild(node.firstChild);\n        }\n\n        node.appendChild(this._closeButton);\n        node.appendChild(this._content);\n    },\n\n    _updatePosition: function() {\n        if (!this._latLng || !this._container) { return; }\n\n        var pos = this._map.project(this._latLng).round(),\n            anchor = this.options.anchor;\n\n        if (!anchor) {\n            var width = this._container.offsetWidth,\n                height = this._container.offsetHeight;\n\n            if (pos.y < height) {\n                anchor = ['top'];\n            } else if (pos.y > this._map.transform.height - height) {\n                anchor = ['bottom'];\n            } else {\n                anchor = [];\n            }\n\n            if (pos.x < width / 2) {\n                anchor.push('left');\n            } else if (pos.x > this._map.transform.width - width / 2) {\n                anchor.push('right');\n            }\n\n            if (anchor.length === 0) {\n                anchor = 'bottom';\n            } else {\n                anchor = anchor.join('-');\n            }\n\n            this.options.anchor = anchor;\n        }\n\n        var anchorTranslate = {\n            'top': 'translate(-50%,0)',\n            'top-left': 'translate(0,0)',\n            'top-right': 'translate(-100%,0)',\n            'bottom': 'translate(-50%,-100%)',\n            'bottom-left': 'translate(0,-100%)',\n            'bottom-right': 'translate(-100%,-100%)',\n            'left': 'translate(0,-50%)',\n            'right': 'translate(-100%,-50%)'\n        };\n\n        var classList = this._container.classList;\n        for (var key in anchorTranslate) {\n            classList.remove('mapboxgl-popup-anchor-' + key);\n        }\n        classList.add('mapboxgl-popup-anchor-' + anchor);\n\n        DOM.setTransform(this._container, anchorTranslate[anchor] + ' translate(' + pos.x + 'px,' + pos.y + 'px)');\n    },\n\n    _onClickClose: function() {\n        this.remove();\n    }\n}","path":"js/ui/popup.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/popup.js#L76-L78"},"returns":[{"title":"returns","description":null,"type":{"type":"NameExpression","name":"LatLng"}}],"name":"getLatLng","memberof":"Popup","scope":"instance","members":{"instance":[],"static":[]},"path":["Popup","getLatLng"]},{"description":"Attaches the popup to a map","tags":[{"title":"param","description":null,"type":{"type":"NameExpression","name":"Map"},"name":"map"},{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Popup"}},{"title":"name","name":"addTo"},{"title":"memberof","description":"Popup"},{"title":"instance"}],"context":{"loc":{"start":{"line":41,"column":4},"end":{"line":49,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/popup.js","code":"{\n    options: {\n        closeButton: true,\n        closeOnClick: true\n    },\n\n    /**\n     * Attaches the popup to a map\n     * @param {Map} map\n     * @returns {Popup} `this`\n     */\n    addTo: function(map) {\n        this._map = map;\n        this._map.on('move', this._updatePosition);\n        if (this.options.closeOnClick) {\n            this._map.on('click', this._onClickClose);\n        }\n        this._update();\n        return this;\n    },\n\n    /**\n     * Removes the popup from the map\n     * @example\n     * var popup = new mapboxgl.Popup().addTo(map);\n     * popup.remove();\n     * @returns {Popup} `this`\n     */\n    remove: function() {\n        if (this._container) {\n            this._container.parentNode.removeChild(this._container);\n        }\n\n        if (this._map) {\n            this._map.off('move', this._updatePosition);\n            this._map.off('click', this._onClickClose);\n            delete this._map;\n        }\n\n        return this;\n    },\n\n    /**\n     * Get the current coordinates of popup element relative to map\n     * @returns {LatLng}\n     */\n    getLatLng: function() {\n        return this._latLng;\n    },\n\n    /**\n     * Set the coordinates of a popup element to a map\n     * @param {LatLng} latlng\n     * @returns {Popup} `this`\n     */\n    setLatLng: function(latlng) {\n        this._latLng = LatLng.convert(latlng);\n        this._update();\n        return this;\n    },\n\n    /**\n     * Popuplate a popup element with text only content\n     * @param {string} text\n     * @returns {Popup} `this`\n     */\n    setText: function(text) {\n        this._content = document.createTextNode(text);\n        this._updateContent();\n        return this;\n    },\n\n    /**\n     * Popuplate a popup element with HTML content\n     * @param {string} html\n     * @returns {Popup} `this`\n     */\n    setHTML: function(html) {\n        this._content = document.createDocumentFragment();\n\n        var temp = document.createElement('body'), child;\n        temp.innerHTML = html;\n        while (true) {\n            child = temp.firstChild;\n            if (!child) break;\n            this._content.appendChild(child);\n        }\n\n        this._updateContent();\n        return this;\n    },\n\n    _update: function() {\n        if (!this._map) { return; }\n\n        if (!this._container) {\n            this._container = DOM.create('div', 'mapboxgl-popup', this._map.getContainer());\n\n            this._tip     = DOM.create('div', 'mapboxgl-popup-tip',     this._container);\n            this._wrapper = DOM.create('div', 'mapboxgl-popup-content', this._container);\n\n            if (this.options.closeButton) {\n                this._closeButton = DOM.create('button', 'mapboxgl-popup-close-button', this._wrapper);\n                this._closeButton.innerHTML = '&#215;';\n                this._closeButton.addEventListener('click', this._onClickClose);\n            }\n        }\n\n        this._updateContent();\n        this._updatePosition();\n    },\n\n    _updateContent: function() {\n        if (!this._content || !this._container) { return; }\n\n        var node = this._wrapper;\n\n        while (node.hasChildNodes()) {\n            node.removeChild(node.firstChild);\n        }\n\n        node.appendChild(this._closeButton);\n        node.appendChild(this._content);\n    },\n\n    _updatePosition: function() {\n        if (!this._latLng || !this._container) { return; }\n\n        var pos = this._map.project(this._latLng).round(),\n            anchor = this.options.anchor;\n\n        if (!anchor) {\n            var width = this._container.offsetWidth,\n                height = this._container.offsetHeight;\n\n            if (pos.y < height) {\n                anchor = ['top'];\n            } else if (pos.y > this._map.transform.height - height) {\n                anchor = ['bottom'];\n            } else {\n                anchor = [];\n            }\n\n            if (pos.x < width / 2) {\n                anchor.push('left');\n            } else if (pos.x > this._map.transform.width - width / 2) {\n                anchor.push('right');\n            }\n\n            if (anchor.length === 0) {\n                anchor = 'bottom';\n            } else {\n                anchor = anchor.join('-');\n            }\n\n            this.options.anchor = anchor;\n        }\n\n        var anchorTranslate = {\n            'top': 'translate(-50%,0)',\n            'top-left': 'translate(0,0)',\n            'top-right': 'translate(-100%,0)',\n            'bottom': 'translate(-50%,-100%)',\n            'bottom-left': 'translate(0,-100%)',\n            'bottom-right': 'translate(-100%,-100%)',\n            'left': 'translate(0,-50%)',\n            'right': 'translate(-100%,-50%)'\n        };\n\n        var classList = this._container.classList;\n        for (var key in anchorTranslate) {\n            classList.remove('mapboxgl-popup-anchor-' + key);\n        }\n        classList.add('mapboxgl-popup-anchor-' + anchor);\n\n        DOM.setTransform(this._container, anchorTranslate[anchor] + ' translate(' + pos.x + 'px,' + pos.y + 'px)');\n    },\n\n    _onClickClose: function() {\n        this.remove();\n    }\n}","path":"js/ui/popup.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/popup.js#L41-L49"},"params":[{"title":"param","description":null,"type":{"type":"NameExpression","name":"Map"},"name":"map"}],"returns":[{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Popup"}}],"name":"addTo","memberof":"Popup","scope":"instance","members":{"instance":[],"static":[]},"path":["Popup","addTo"]}],"static":[]},"path":["Popup"]},{"description":"Creates a map instance.","tags":[{"title":"class","description":null,"type":null,"name":"Map"},{"title":"param","description":null,"type":{"type":"NameExpression","name":"Object"},"name":"options"},{"title":"param","description":"HTML element to initialize the map in (or element id as string)","type":{"type":"NameExpression","name":"String"},"name":"options.container"},{"title":"name","name":"Map"},{"title":"kind","kind":"class"}],"context":{"loc":{"start":{"line":43,"column":0},"end":{"line":91,"column":2}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"'use strict';\n\nvar Canvas = require('../util/canvas');\nvar util = require('../util/util');\nvar browser = require('../util/browser');\nvar Evented = require('../util/evented');\nvar DOM = require('../util/dom');\n\nvar Style = require('../style/style');\nvar AnimationLoop = require('../style/animation_loop');\nvar GLPainter = require('../render/painter');\n\nvar Transform = require('../geo/transform');\nvar Hash = require('./hash');\nvar Handlers = require('./handlers');\nvar Easings = require('./easings');\nvar LatLng = require('../geo/lat_lng');\nvar LatLngBounds = require('../geo/lat_lng_bounds');\nvar Point = require('point-geometry');\nvar Attribution = require('./control/attribution');\n\n/**\n * Creates a map instance.\n * @class Map\n * @param {Object} options\n * @param {String} options.container HTML element to initialize the map in (or element id as string)\n * @param {Number} [options.minZoom=0] Minimum zoom of the map\n * @param {Number} [options.maxZoom=20] Maximum zoom of the map\n * @param {Object} options.style Map style and data source definition (either a JSON object or a JSON URL), described in the [style reference](https://mapbox.com/mapbox-gl-style-spec/)\n * @param {Boolean} [options.hash=false] If `true`, the map will track and update the page URL according to map position\n * @param {Boolean} [options.interactive=true] If `false`, no mouse, touch, or keyboard listeners are attached to the map, so it will not respond to input\n * @param {Array} options.classes Style class names with which to initialize the map\n * @param {Boolean} [options.failIfMajorPerformanceCaveat=false] If `true`, map creation will fail if the implementation determines that the performance of the created WebGL context would be dramatically lower than expected.\n * @example\n * var map = new mapboxgl.Map({\n *   container: 'map',\n *   center: [37.772537, -122.420679],\n *   zoom: 13,\n *   style: style_object,\n *   hash: true\n * });\n */\nvar Map = module.exports = function(options) {\n\n    options = this.options = util.inherit(this.options, options);\n\n    this.animationLoop = new AnimationLoop();\n    this.transform = new Transform(options.minZoom, options.maxZoom);\n\n    if (options.maxBounds) {\n        var b = LatLngBounds.convert(options.maxBounds);\n        this.transform.latRange = [b.getSouth(), b.getNorth()];\n        this.transform.lngRange = [b.getWest(), b.getEast()];\n    }\n\n    util.bindAll([\n        '_forwardStyleEvent',\n        '_forwardSourceEvent',\n        '_forwardLayerEvent',\n        '_forwardTileEvent',\n        '_onStyleLoad',\n        '_onStyleChange',\n        '_onSourceAdd',\n        '_onSourceRemove',\n        '_onSourceUpdate',\n        'update',\n        'render'\n    ], this);\n\n    this._setupContainer();\n    this._setupControlPos();\n    this._setupPainter();\n\n    this.handlers = options.interactive && new Handlers(this);\n\n    this._hash = options.hash && (new Hash()).addTo(this);\n    // don't set position from options if set through hash\n    if (!this._hash || !this._hash._onHashChange()) {\n        this.setView(options.center, options.zoom, options.bearing, options.pitch);\n    }\n\n    this.sources = {};\n    this.stacks = {};\n    this._classes = {};\n\n    this.resize();\n\n    if (options.classes) this.setClasses(options.classes);\n    if (options.style) this.setStyle(options.style);\n    if (options.attributionControl) this.addControl(new Attribution());\n};\n\nutil.extend(Map.prototype, Evented);\nutil.extend(Map.prototype, Easings);\nutil.extend(Map.prototype, /** @lends Map.prototype */{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n});\n\nutil.extendAll(Map.prototype, {\n\n    // debug code\n    _debug: false,\n    get debug() { return this._debug; },\n    set debug(value) { this._debug = value; this.update(); },\n\n    // show collision boxes\n    _collisionDebug: false,\n    get collisionDebug() { return this._collisionDebug; },\n    set collisionDebug(value) {\n        this._collisionDebug = value;\n        for (var i in this.style.sources) {\n            this.style.sources[i].reload();\n        }\n        this.update();\n    },\n\n    // continuous repaint\n    _repaint: false,\n    get repaint() { return this._repaint; },\n    set repaint(value) { this._repaint = value; this.update(); },\n\n    // show vertices\n    _vertices: false,\n    get vertices() { return this._vertices; },\n    set vertices(value) { this._vertices = value; this.update(); }\n});","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L43-L91"},"params":[{"title":"param","description":null,"type":{"type":"NameExpression","name":"Object"},"name":"options"},{"title":"param","description":"HTML element to initialize the map in (or element id as string)","type":{"type":"NameExpression","name":"String"},"name":"options.container"}],"name":"Map","kind":"class","members":{"instance":[{"description":"Zooms to a certain zoom level with easing.","tags":[{"title":"param","description":null,"type":{"type":"NameExpression","name":"Number"},"name":"zoom"},{"title":"param","description":null,"type":null,"name":"animOptions"},{"title":"fires","description":"movestart"},{"title":"fires","description":"moveend"},{"title":"returns","description":null,"type":{"type":"NameExpression","name":"this"}},{"title":"name","name":"zoomTo"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":112,"column":4},"end":{"line":160,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/easings.js","code":"{\n    isEasing: function() {\n        return !!this._abortFn;\n    },\n\n    /**\n     * Stop current animation\n     *\n     * @returns {this}\n     */\n    stop: function() {\n        if (this._abortFn) {\n            this._abortFn.call(this);\n            delete this._abortFn;\n\n            this._finishFn.call(this);\n            delete this._finishFn;\n        }\n        return this;\n    },\n\n    _ease: function(frame, finish, options) {\n        this._finishFn = finish;\n        this._abortFn = browser.timed(function (t) {\n            frame.call(this, options.easing(t));\n            if (t === 1) {\n                delete this._abortFn;\n                this._finishFn.call(this);\n                delete this._finishFn;\n            }\n        }, options.animate === false ? 0 : options.duration, this);\n    },\n\n    /**\n     * Pan by a certain number of pixels\n     *\n     * @param {Array} offset [x, y]\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    panBy: function(offset, options) {\n        this.panTo(this.transform.center, util.extend({offset: Point.convert(offset).mult(-1)}, options));\n        return this;\n    },\n\n    /**\n     * Pan to a certain location with easing\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    panTo: function(latlng, options) {\n        this.stop();\n\n        latlng = LatLng.convert(latlng);\n\n        options = util.extend({\n            duration: 500,\n            easing: util.ease,\n            offset: [0, 0]\n        }, options);\n\n        var tr = this.transform,\n            offset = Point.convert(options.offset).rotate(-tr.angle),\n            from = tr.point,\n            to = tr.project(latlng).sub(offset);\n\n        if (!options.noMoveStart) {\n            this.fire('movestart');\n        }\n\n        this._ease(function(k) {\n            tr.center = tr.unproject(from.add(to.sub(from).mult(k)));\n            this._move();\n        }, function() {\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Zooms to a certain zoom level with easing.\n     *\n     * @param {Number} zoom\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomTo: function(zoom, options) {\n        this.stop();\n\n        options = util.extend({\n            duration: 500\n        }, options);\n\n        options.easing = this._updateEasing(options.duration, zoom, options.easing);\n\n        var tr = this.transform,\n            around = tr.center,\n            startZoom = tr.zoom;\n\n        if (options.around) {\n            around = LatLng.convert(options.around);\n        } else if (options.offset) {\n            around = tr.pointLocation(tr.centerPoint.add(Point.convert(options.offset)));\n        }\n\n        if (options.animate === false) options.duration = 0;\n\n        if (!this.zooming) {\n            this.zooming = true;\n            this.fire('movestart');\n        }\n\n        this._ease(function(k) {\n            tr.setZoomAround(interpolate(startZoom, zoom, k), around);\n            this.animationLoop.set(300); // text fading\n            this._move(true);\n        }, function() {\n            this.ease = null;\n            if (options.duration >= 200) {\n                this.zooming = false;\n                this.fire('moveend');\n            }\n        }, options);\n\n        if (options.duration < 200) {\n            clearTimeout(this._onZoomEnd);\n            this._onZoomEnd = setTimeout(function() {\n                this.zooming = false;\n                this._rerender();\n                this.fire('moveend');\n            }.bind(this), 200);\n        }\n\n        return this;\n    },\n\n    /**\n     * Zoom in by 1 level\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomIn: function(options) {\n        this.zoomTo(this.getZoom() + 1, options);\n    },\n\n    /**\n     * Zoom out by 1 level\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomOut: function(options) {\n        this.zoomTo(this.getZoom() - 1, options);\n    },\n\n    /**\n     * Rotate bearing by a certain number of degrees with easing\n     *\n     * @param {Number} bearing\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    rotateTo: function(bearing, options) {\n        this.stop();\n\n        options = util.extend({\n            duration: 500,\n            easing: util.ease\n        }, options);\n\n        var tr = this.transform,\n            start = this.getBearing(),\n            around = tr.center;\n\n        if (options.around) {\n            around = LatLng.convert(options.around);\n        } else if (options.offset) {\n            around = tr.pointLocation(tr.centerPoint.add(Point.convert(options.offset)));\n        }\n\n        bearing = this._normalizeBearing(bearing, start);\n\n        this.rotating = true;\n        this.fire('movestart');\n\n        this._ease(function(k) {\n            tr.setBearingAround(interpolate(start, bearing, k), around);\n            this._move(false, true);\n        }, function() {\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Sets map bearing to 0 (north) with easing\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    resetNorth: function(options) {\n        return this.rotateTo(0, util.extend({duration: 1000}, options));\n    },\n\n    /**\n     * Zoom to contain certain geographical bounds\n     *\n     * @param {Array} bounds [[minLat, minLng], [maxLat, maxLng]]\n     * @param {Object} options\n     * @param {Number} [options.speed=1.2] How fast animation occurs\n     * @param {Number} [options.curve=1.42] How much zooming out occurs during animation\n     * @param {Function} options.easing\n     * @param {Number} options.padding how much padding there is around the given bounds on each side in pixels\n     * @param {Number} options.maxZoom\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    fitBounds: function(bounds, options) {\n\n        options = util.extend({\n            padding: 0,\n            offset: [0, 0],\n            maxZoom: Infinity\n        }, options);\n\n        bounds = LatLngBounds.convert(bounds);\n\n        var offset = Point.convert(options.offset),\n            tr = this.transform,\n            nw = tr.project(bounds.getNorthWest()),\n            se = tr.project(bounds.getSouthEast()),\n            size = se.sub(nw),\n            center = tr.unproject(nw.add(se).div(2)),\n\n            scaleX = (tr.width - options.padding * 2 - Math.abs(offset.x) * 2) / size.x,\n            scaleY = (tr.height - options.padding * 2 - Math.abs(offset.y) * 2) / size.y,\n\n            zoom = Math.min(tr.scaleZoom(tr.scale * Math.min(scaleX, scaleY)), options.maxZoom);\n\n        return options.linear ?\n            this.easeTo(center, zoom, 0, options) :\n            this.flyTo(center, zoom, 0, options);\n    },\n\n    /**\n     * Easing animation to a specified location/zoom/bearing\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {Number} zoom\n     * @param {Number} bearing\n     * @param {Number} pitch\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    easeTo: function(latlng, zoom, bearing, pitch, options) {\n        this.stop();\n\n        options = util.extend({\n            offset: [0, 0],\n            duration: 500,\n            easing: util.ease\n        }, options);\n\n        var tr = this.transform,\n            offset = Point.convert(options.offset).rotate(-tr.angle),\n            startZoom = this.getZoom(),\n            startBearing = this.getBearing(),\n            startPitch = this.getPitch();\n\n        latlng = LatLng.convert(latlng);\n        zoom = zoom === undefined ? startZoom : zoom;\n        bearing = bearing === undefined ? startBearing : this._normalizeBearing(bearing, startBearing);\n        pitch = pitch === undefined ? startPitch : pitch;\n\n        var scale = tr.zoomScale(zoom - startZoom),\n            from = tr.point,\n            to = latlng ? tr.project(latlng).sub(offset.div(scale)) : tr.point,\n            around;\n\n        if (zoom !== startZoom) {\n            around = tr.pointLocation(tr.centerPoint.add(to.sub(from).div(1 - 1 / scale)));\n            this.zooming = true;\n        }\n        if (startBearing !== bearing) this.rotating = true;\n\n        this.fire('movestart');\n\n        this._ease(function (k) {\n            if (zoom !== startZoom) {\n                tr.setZoomAround(interpolate(startZoom, zoom, k), around);\n            } else {\n                tr.center = tr.unproject(from.add(to.sub(from).mult(k)));\n            }\n\n            if (bearing !== startBearing) {\n                tr.bearing = interpolate(startBearing, bearing, k);\n            }\n\n            if (pitch !== startPitch) {\n                tr.pitch = interpolate(startPitch, pitch, k);\n            }\n\n            this.animationLoop.set(300); // text fading\n            this._move(zoom !== startZoom, bearing !== startBearing);\n        }, function() {\n            this.zooming = false;\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Flying animation to a specified location/zoom/bearing with automatic curve\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {Number} zoom\n     * @param {Number} bearing\n     * @param {Object} options\n     * @param {Number} [options.speed=1.2] How fast animation occurs\n     * @param {Number} [options.curve=1.42] How much zooming out occurs during animation\n     * @param {Function} options.easing\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    flyTo: function(latlng, zoom, bearing, options) {\n        this.stop();\n\n        options = util.extend({\n            offset: [0, 0],\n            speed: 1.2,\n            curve: 1.42,\n            easing: util.ease\n        }, options);\n\n        latlng = LatLng.convert(latlng);\n\n        var offset = Point.convert(options.offset),\n            tr = this.transform,\n            startZoom = this.getZoom(),\n            startBearing = this.getBearing();\n\n        zoom = zoom === undefined ? startZoom : zoom;\n        bearing = bearing === undefined ? startBearing : this._normalizeBearing(bearing, startBearing);\n\n        var scale = tr.zoomScale(zoom - startZoom),\n            from = tr.point,\n            to = tr.project(latlng).sub(offset.div(scale));\n\n        if (options.animate === false) {\n            return this.setView(latlng, zoom, bearing, this.getPitch());\n        }\n\n        var startWorldSize = tr.worldSize,\n            rho = options.curve,\n            V = options.speed,\n\n            w0 = Math.max(tr.width, tr.height),\n            w1 = w0 / scale,\n            u1 = to.sub(from).mag(),\n            rho2 = rho * rho;\n\n        function r(i) {\n            var b = (w1 * w1 - w0 * w0 + (i ? -1 : 1) * rho2 * rho2 * u1 * u1) / (2 * (i ? w1 : w0) * rho2 * u1);\n            return Math.log(Math.sqrt(b * b + 1) - b);\n        }\n\n        function sinh(n) { return (Math.exp(n) - Math.exp(-n)) / 2; }\n        function cosh(n) { return (Math.exp(n) + Math.exp(-n)) / 2; }\n        function tanh(n) { return sinh(n) / cosh(n); }\n\n        var r0 = r(0),\n            w = function (s) { return (cosh(r0) / cosh(r0 + rho * s)); },\n            u = function (s) { return w0 * ((cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2) / u1; },\n            S = (r(1) - r0) / rho;\n\n        if (Math.abs(u1) < 0.000001) {\n            if (Math.abs(w0 - w1) < 0.000001) return this;\n\n            var k = w1 < w0 ? -1 : 1;\n            S = Math.abs(Math.log(w1 / w0)) / rho;\n\n            u = function() { return 0; };\n            w = function(s) { return Math.exp(k * rho * s); };\n        }\n\n        options.duration = 1000 * S / V;\n\n        this.zooming = true;\n        if (startBearing !== bearing) this.rotating = true;\n\n        this.fire('movestart');\n\n        this._ease(function (k) {\n            var s = k * S,\n                us = u(s);\n\n            tr.zoom = startZoom + tr.scaleZoom(1 / w(s));\n            tr.center = tr.unproject(from.add(to.sub(from).mult(us)), startWorldSize);\n\n            if (bearing !== startBearing) {\n                tr.bearing = interpolate(startBearing, bearing, k);\n            }\n\n            this.animationLoop.set(300); // text fading\n\n            this._move(true, bearing !== startBearing);\n        }, function() {\n            this.zooming = false;\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    // convert bearing so that it's numerically close to the current one so that it interpolates properly\n    _normalizeBearing: function(bearing, currentBearing) {\n        bearing = util.wrap(bearing, -180, 180);\n        var diff = Math.abs(bearing - currentBearing);\n        if (Math.abs(bearing - 360 - currentBearing) < diff) bearing -= 360;\n        if (Math.abs(bearing + 360 - currentBearing) < diff) bearing += 360;\n        return bearing;\n    },\n\n    _updateEasing: function(duration, zoom, bezier) {\n        var easing;\n\n        if (this.ease) {\n            var ease = this.ease,\n                t = (Date.now() - ease.start) / ease.duration,\n                speed = ease.easing(t + 0.01) - ease.easing(t),\n\n                // Quick hack to make new bezier that is continuous with last\n                x = 0.27 / Math.sqrt(speed * speed + 0.0001) * 0.01,\n                y = Math.sqrt(0.27 * 0.27 - x * x);\n\n            easing = util.bezier(x, y, 0.25, 1);\n        } else {\n            easing = bezier ? util.bezier.apply(util, bezier) : util.ease;\n        }\n\n        // store information on current easing\n        this.ease = {\n            start: (new Date()).getTime(),\n            to: Math.pow(2, zoom),\n            duration: duration,\n            easing: easing\n        };\n\n        return easing;\n    }\n}","path":"js/ui/easings.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/easings.js#L112-L160"},"params":[{"title":"param","description":null,"type":{"type":"NameExpression","name":"Number"},"name":"zoom"},{"title":"param","description":null,"type":null,"name":"animOptions"}],"returns":[{"title":"returns","description":null,"type":{"type":"NameExpression","name":"this"}}],"name":"zoomTo","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","zoomTo"]},{"description":"Zoom out by 1 level","tags":[{"title":"param","description":null,"type":null,"name":"animOptions"},{"title":"fires","description":"movestart"},{"title":"fires","description":"moveend"},{"title":"returns","description":null,"type":{"type":"NameExpression","name":"this"}},{"title":"name","name":"zoomOut"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":182,"column":4},"end":{"line":184,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/easings.js","code":"{\n    isEasing: function() {\n        return !!this._abortFn;\n    },\n\n    /**\n     * Stop current animation\n     *\n     * @returns {this}\n     */\n    stop: function() {\n        if (this._abortFn) {\n            this._abortFn.call(this);\n            delete this._abortFn;\n\n            this._finishFn.call(this);\n            delete this._finishFn;\n        }\n        return this;\n    },\n\n    _ease: function(frame, finish, options) {\n        this._finishFn = finish;\n        this._abortFn = browser.timed(function (t) {\n            frame.call(this, options.easing(t));\n            if (t === 1) {\n                delete this._abortFn;\n                this._finishFn.call(this);\n                delete this._finishFn;\n            }\n        }, options.animate === false ? 0 : options.duration, this);\n    },\n\n    /**\n     * Pan by a certain number of pixels\n     *\n     * @param {Array} offset [x, y]\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    panBy: function(offset, options) {\n        this.panTo(this.transform.center, util.extend({offset: Point.convert(offset).mult(-1)}, options));\n        return this;\n    },\n\n    /**\n     * Pan to a certain location with easing\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    panTo: function(latlng, options) {\n        this.stop();\n\n        latlng = LatLng.convert(latlng);\n\n        options = util.extend({\n            duration: 500,\n            easing: util.ease,\n            offset: [0, 0]\n        }, options);\n\n        var tr = this.transform,\n            offset = Point.convert(options.offset).rotate(-tr.angle),\n            from = tr.point,\n            to = tr.project(latlng).sub(offset);\n\n        if (!options.noMoveStart) {\n            this.fire('movestart');\n        }\n\n        this._ease(function(k) {\n            tr.center = tr.unproject(from.add(to.sub(from).mult(k)));\n            this._move();\n        }, function() {\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Zooms to a certain zoom level with easing.\n     *\n     * @param {Number} zoom\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomTo: function(zoom, options) {\n        this.stop();\n\n        options = util.extend({\n            duration: 500\n        }, options);\n\n        options.easing = this._updateEasing(options.duration, zoom, options.easing);\n\n        var tr = this.transform,\n            around = tr.center,\n            startZoom = tr.zoom;\n\n        if (options.around) {\n            around = LatLng.convert(options.around);\n        } else if (options.offset) {\n            around = tr.pointLocation(tr.centerPoint.add(Point.convert(options.offset)));\n        }\n\n        if (options.animate === false) options.duration = 0;\n\n        if (!this.zooming) {\n            this.zooming = true;\n            this.fire('movestart');\n        }\n\n        this._ease(function(k) {\n            tr.setZoomAround(interpolate(startZoom, zoom, k), around);\n            this.animationLoop.set(300); // text fading\n            this._move(true);\n        }, function() {\n            this.ease = null;\n            if (options.duration >= 200) {\n                this.zooming = false;\n                this.fire('moveend');\n            }\n        }, options);\n\n        if (options.duration < 200) {\n            clearTimeout(this._onZoomEnd);\n            this._onZoomEnd = setTimeout(function() {\n                this.zooming = false;\n                this._rerender();\n                this.fire('moveend');\n            }.bind(this), 200);\n        }\n\n        return this;\n    },\n\n    /**\n     * Zoom in by 1 level\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomIn: function(options) {\n        this.zoomTo(this.getZoom() + 1, options);\n    },\n\n    /**\n     * Zoom out by 1 level\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomOut: function(options) {\n        this.zoomTo(this.getZoom() - 1, options);\n    },\n\n    /**\n     * Rotate bearing by a certain number of degrees with easing\n     *\n     * @param {Number} bearing\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    rotateTo: function(bearing, options) {\n        this.stop();\n\n        options = util.extend({\n            duration: 500,\n            easing: util.ease\n        }, options);\n\n        var tr = this.transform,\n            start = this.getBearing(),\n            around = tr.center;\n\n        if (options.around) {\n            around = LatLng.convert(options.around);\n        } else if (options.offset) {\n            around = tr.pointLocation(tr.centerPoint.add(Point.convert(options.offset)));\n        }\n\n        bearing = this._normalizeBearing(bearing, start);\n\n        this.rotating = true;\n        this.fire('movestart');\n\n        this._ease(function(k) {\n            tr.setBearingAround(interpolate(start, bearing, k), around);\n            this._move(false, true);\n        }, function() {\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Sets map bearing to 0 (north) with easing\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    resetNorth: function(options) {\n        return this.rotateTo(0, util.extend({duration: 1000}, options));\n    },\n\n    /**\n     * Zoom to contain certain geographical bounds\n     *\n     * @param {Array} bounds [[minLat, minLng], [maxLat, maxLng]]\n     * @param {Object} options\n     * @param {Number} [options.speed=1.2] How fast animation occurs\n     * @param {Number} [options.curve=1.42] How much zooming out occurs during animation\n     * @param {Function} options.easing\n     * @param {Number} options.padding how much padding there is around the given bounds on each side in pixels\n     * @param {Number} options.maxZoom\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    fitBounds: function(bounds, options) {\n\n        options = util.extend({\n            padding: 0,\n            offset: [0, 0],\n            maxZoom: Infinity\n        }, options);\n\n        bounds = LatLngBounds.convert(bounds);\n\n        var offset = Point.convert(options.offset),\n            tr = this.transform,\n            nw = tr.project(bounds.getNorthWest()),\n            se = tr.project(bounds.getSouthEast()),\n            size = se.sub(nw),\n            center = tr.unproject(nw.add(se).div(2)),\n\n            scaleX = (tr.width - options.padding * 2 - Math.abs(offset.x) * 2) / size.x,\n            scaleY = (tr.height - options.padding * 2 - Math.abs(offset.y) * 2) / size.y,\n\n            zoom = Math.min(tr.scaleZoom(tr.scale * Math.min(scaleX, scaleY)), options.maxZoom);\n\n        return options.linear ?\n            this.easeTo(center, zoom, 0, options) :\n            this.flyTo(center, zoom, 0, options);\n    },\n\n    /**\n     * Easing animation to a specified location/zoom/bearing\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {Number} zoom\n     * @param {Number} bearing\n     * @param {Number} pitch\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    easeTo: function(latlng, zoom, bearing, pitch, options) {\n        this.stop();\n\n        options = util.extend({\n            offset: [0, 0],\n            duration: 500,\n            easing: util.ease\n        }, options);\n\n        var tr = this.transform,\n            offset = Point.convert(options.offset).rotate(-tr.angle),\n            startZoom = this.getZoom(),\n            startBearing = this.getBearing(),\n            startPitch = this.getPitch();\n\n        latlng = LatLng.convert(latlng);\n        zoom = zoom === undefined ? startZoom : zoom;\n        bearing = bearing === undefined ? startBearing : this._normalizeBearing(bearing, startBearing);\n        pitch = pitch === undefined ? startPitch : pitch;\n\n        var scale = tr.zoomScale(zoom - startZoom),\n            from = tr.point,\n            to = latlng ? tr.project(latlng).sub(offset.div(scale)) : tr.point,\n            around;\n\n        if (zoom !== startZoom) {\n            around = tr.pointLocation(tr.centerPoint.add(to.sub(from).div(1 - 1 / scale)));\n            this.zooming = true;\n        }\n        if (startBearing !== bearing) this.rotating = true;\n\n        this.fire('movestart');\n\n        this._ease(function (k) {\n            if (zoom !== startZoom) {\n                tr.setZoomAround(interpolate(startZoom, zoom, k), around);\n            } else {\n                tr.center = tr.unproject(from.add(to.sub(from).mult(k)));\n            }\n\n            if (bearing !== startBearing) {\n                tr.bearing = interpolate(startBearing, bearing, k);\n            }\n\n            if (pitch !== startPitch) {\n                tr.pitch = interpolate(startPitch, pitch, k);\n            }\n\n            this.animationLoop.set(300); // text fading\n            this._move(zoom !== startZoom, bearing !== startBearing);\n        }, function() {\n            this.zooming = false;\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Flying animation to a specified location/zoom/bearing with automatic curve\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {Number} zoom\n     * @param {Number} bearing\n     * @param {Object} options\n     * @param {Number} [options.speed=1.2] How fast animation occurs\n     * @param {Number} [options.curve=1.42] How much zooming out occurs during animation\n     * @param {Function} options.easing\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    flyTo: function(latlng, zoom, bearing, options) {\n        this.stop();\n\n        options = util.extend({\n            offset: [0, 0],\n            speed: 1.2,\n            curve: 1.42,\n            easing: util.ease\n        }, options);\n\n        latlng = LatLng.convert(latlng);\n\n        var offset = Point.convert(options.offset),\n            tr = this.transform,\n            startZoom = this.getZoom(),\n            startBearing = this.getBearing();\n\n        zoom = zoom === undefined ? startZoom : zoom;\n        bearing = bearing === undefined ? startBearing : this._normalizeBearing(bearing, startBearing);\n\n        var scale = tr.zoomScale(zoom - startZoom),\n            from = tr.point,\n            to = tr.project(latlng).sub(offset.div(scale));\n\n        if (options.animate === false) {\n            return this.setView(latlng, zoom, bearing, this.getPitch());\n        }\n\n        var startWorldSize = tr.worldSize,\n            rho = options.curve,\n            V = options.speed,\n\n            w0 = Math.max(tr.width, tr.height),\n            w1 = w0 / scale,\n            u1 = to.sub(from).mag(),\n            rho2 = rho * rho;\n\n        function r(i) {\n            var b = (w1 * w1 - w0 * w0 + (i ? -1 : 1) * rho2 * rho2 * u1 * u1) / (2 * (i ? w1 : w0) * rho2 * u1);\n            return Math.log(Math.sqrt(b * b + 1) - b);\n        }\n\n        function sinh(n) { return (Math.exp(n) - Math.exp(-n)) / 2; }\n        function cosh(n) { return (Math.exp(n) + Math.exp(-n)) / 2; }\n        function tanh(n) { return sinh(n) / cosh(n); }\n\n        var r0 = r(0),\n            w = function (s) { return (cosh(r0) / cosh(r0 + rho * s)); },\n            u = function (s) { return w0 * ((cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2) / u1; },\n            S = (r(1) - r0) / rho;\n\n        if (Math.abs(u1) < 0.000001) {\n            if (Math.abs(w0 - w1) < 0.000001) return this;\n\n            var k = w1 < w0 ? -1 : 1;\n            S = Math.abs(Math.log(w1 / w0)) / rho;\n\n            u = function() { return 0; };\n            w = function(s) { return Math.exp(k * rho * s); };\n        }\n\n        options.duration = 1000 * S / V;\n\n        this.zooming = true;\n        if (startBearing !== bearing) this.rotating = true;\n\n        this.fire('movestart');\n\n        this._ease(function (k) {\n            var s = k * S,\n                us = u(s);\n\n            tr.zoom = startZoom + tr.scaleZoom(1 / w(s));\n            tr.center = tr.unproject(from.add(to.sub(from).mult(us)), startWorldSize);\n\n            if (bearing !== startBearing) {\n                tr.bearing = interpolate(startBearing, bearing, k);\n            }\n\n            this.animationLoop.set(300); // text fading\n\n            this._move(true, bearing !== startBearing);\n        }, function() {\n            this.zooming = false;\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    // convert bearing so that it's numerically close to the current one so that it interpolates properly\n    _normalizeBearing: function(bearing, currentBearing) {\n        bearing = util.wrap(bearing, -180, 180);\n        var diff = Math.abs(bearing - currentBearing);\n        if (Math.abs(bearing - 360 - currentBearing) < diff) bearing -= 360;\n        if (Math.abs(bearing + 360 - currentBearing) < diff) bearing += 360;\n        return bearing;\n    },\n\n    _updateEasing: function(duration, zoom, bezier) {\n        var easing;\n\n        if (this.ease) {\n            var ease = this.ease,\n                t = (Date.now() - ease.start) / ease.duration,\n                speed = ease.easing(t + 0.01) - ease.easing(t),\n\n                // Quick hack to make new bezier that is continuous with last\n                x = 0.27 / Math.sqrt(speed * speed + 0.0001) * 0.01,\n                y = Math.sqrt(0.27 * 0.27 - x * x);\n\n            easing = util.bezier(x, y, 0.25, 1);\n        } else {\n            easing = bezier ? util.bezier.apply(util, bezier) : util.ease;\n        }\n\n        // store information on current easing\n        this.ease = {\n            start: (new Date()).getTime(),\n            to: Math.pow(2, zoom),\n            duration: duration,\n            easing: easing\n        };\n\n        return easing;\n    }\n}","path":"js/ui/easings.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/easings.js#L182-L184"},"params":[{"title":"param","description":null,"type":null,"name":"animOptions"}],"returns":[{"title":"returns","description":null,"type":{"type":"NameExpression","name":"this"}}],"name":"zoomOut","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","zoomOut"]},{"description":"Zoom in by 1 level","tags":[{"title":"param","description":null,"type":null,"name":"animOptions"},{"title":"fires","description":"movestart"},{"title":"fires","description":"moveend"},{"title":"returns","description":null,"type":{"type":"NameExpression","name":"this"}},{"title":"name","name":"zoomIn"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":170,"column":4},"end":{"line":172,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/easings.js","code":"{\n    isEasing: function() {\n        return !!this._abortFn;\n    },\n\n    /**\n     * Stop current animation\n     *\n     * @returns {this}\n     */\n    stop: function() {\n        if (this._abortFn) {\n            this._abortFn.call(this);\n            delete this._abortFn;\n\n            this._finishFn.call(this);\n            delete this._finishFn;\n        }\n        return this;\n    },\n\n    _ease: function(frame, finish, options) {\n        this._finishFn = finish;\n        this._abortFn = browser.timed(function (t) {\n            frame.call(this, options.easing(t));\n            if (t === 1) {\n                delete this._abortFn;\n                this._finishFn.call(this);\n                delete this._finishFn;\n            }\n        }, options.animate === false ? 0 : options.duration, this);\n    },\n\n    /**\n     * Pan by a certain number of pixels\n     *\n     * @param {Array} offset [x, y]\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    panBy: function(offset, options) {\n        this.panTo(this.transform.center, util.extend({offset: Point.convert(offset).mult(-1)}, options));\n        return this;\n    },\n\n    /**\n     * Pan to a certain location with easing\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    panTo: function(latlng, options) {\n        this.stop();\n\n        latlng = LatLng.convert(latlng);\n\n        options = util.extend({\n            duration: 500,\n            easing: util.ease,\n            offset: [0, 0]\n        }, options);\n\n        var tr = this.transform,\n            offset = Point.convert(options.offset).rotate(-tr.angle),\n            from = tr.point,\n            to = tr.project(latlng).sub(offset);\n\n        if (!options.noMoveStart) {\n            this.fire('movestart');\n        }\n\n        this._ease(function(k) {\n            tr.center = tr.unproject(from.add(to.sub(from).mult(k)));\n            this._move();\n        }, function() {\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Zooms to a certain zoom level with easing.\n     *\n     * @param {Number} zoom\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomTo: function(zoom, options) {\n        this.stop();\n\n        options = util.extend({\n            duration: 500\n        }, options);\n\n        options.easing = this._updateEasing(options.duration, zoom, options.easing);\n\n        var tr = this.transform,\n            around = tr.center,\n            startZoom = tr.zoom;\n\n        if (options.around) {\n            around = LatLng.convert(options.around);\n        } else if (options.offset) {\n            around = tr.pointLocation(tr.centerPoint.add(Point.convert(options.offset)));\n        }\n\n        if (options.animate === false) options.duration = 0;\n\n        if (!this.zooming) {\n            this.zooming = true;\n            this.fire('movestart');\n        }\n\n        this._ease(function(k) {\n            tr.setZoomAround(interpolate(startZoom, zoom, k), around);\n            this.animationLoop.set(300); // text fading\n            this._move(true);\n        }, function() {\n            this.ease = null;\n            if (options.duration >= 200) {\n                this.zooming = false;\n                this.fire('moveend');\n            }\n        }, options);\n\n        if (options.duration < 200) {\n            clearTimeout(this._onZoomEnd);\n            this._onZoomEnd = setTimeout(function() {\n                this.zooming = false;\n                this._rerender();\n                this.fire('moveend');\n            }.bind(this), 200);\n        }\n\n        return this;\n    },\n\n    /**\n     * Zoom in by 1 level\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomIn: function(options) {\n        this.zoomTo(this.getZoom() + 1, options);\n    },\n\n    /**\n     * Zoom out by 1 level\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomOut: function(options) {\n        this.zoomTo(this.getZoom() - 1, options);\n    },\n\n    /**\n     * Rotate bearing by a certain number of degrees with easing\n     *\n     * @param {Number} bearing\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    rotateTo: function(bearing, options) {\n        this.stop();\n\n        options = util.extend({\n            duration: 500,\n            easing: util.ease\n        }, options);\n\n        var tr = this.transform,\n            start = this.getBearing(),\n            around = tr.center;\n\n        if (options.around) {\n            around = LatLng.convert(options.around);\n        } else if (options.offset) {\n            around = tr.pointLocation(tr.centerPoint.add(Point.convert(options.offset)));\n        }\n\n        bearing = this._normalizeBearing(bearing, start);\n\n        this.rotating = true;\n        this.fire('movestart');\n\n        this._ease(function(k) {\n            tr.setBearingAround(interpolate(start, bearing, k), around);\n            this._move(false, true);\n        }, function() {\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Sets map bearing to 0 (north) with easing\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    resetNorth: function(options) {\n        return this.rotateTo(0, util.extend({duration: 1000}, options));\n    },\n\n    /**\n     * Zoom to contain certain geographical bounds\n     *\n     * @param {Array} bounds [[minLat, minLng], [maxLat, maxLng]]\n     * @param {Object} options\n     * @param {Number} [options.speed=1.2] How fast animation occurs\n     * @param {Number} [options.curve=1.42] How much zooming out occurs during animation\n     * @param {Function} options.easing\n     * @param {Number} options.padding how much padding there is around the given bounds on each side in pixels\n     * @param {Number} options.maxZoom\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    fitBounds: function(bounds, options) {\n\n        options = util.extend({\n            padding: 0,\n            offset: [0, 0],\n            maxZoom: Infinity\n        }, options);\n\n        bounds = LatLngBounds.convert(bounds);\n\n        var offset = Point.convert(options.offset),\n            tr = this.transform,\n            nw = tr.project(bounds.getNorthWest()),\n            se = tr.project(bounds.getSouthEast()),\n            size = se.sub(nw),\n            center = tr.unproject(nw.add(se).div(2)),\n\n            scaleX = (tr.width - options.padding * 2 - Math.abs(offset.x) * 2) / size.x,\n            scaleY = (tr.height - options.padding * 2 - Math.abs(offset.y) * 2) / size.y,\n\n            zoom = Math.min(tr.scaleZoom(tr.scale * Math.min(scaleX, scaleY)), options.maxZoom);\n\n        return options.linear ?\n            this.easeTo(center, zoom, 0, options) :\n            this.flyTo(center, zoom, 0, options);\n    },\n\n    /**\n     * Easing animation to a specified location/zoom/bearing\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {Number} zoom\n     * @param {Number} bearing\n     * @param {Number} pitch\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    easeTo: function(latlng, zoom, bearing, pitch, options) {\n        this.stop();\n\n        options = util.extend({\n            offset: [0, 0],\n            duration: 500,\n            easing: util.ease\n        }, options);\n\n        var tr = this.transform,\n            offset = Point.convert(options.offset).rotate(-tr.angle),\n            startZoom = this.getZoom(),\n            startBearing = this.getBearing(),\n            startPitch = this.getPitch();\n\n        latlng = LatLng.convert(latlng);\n        zoom = zoom === undefined ? startZoom : zoom;\n        bearing = bearing === undefined ? startBearing : this._normalizeBearing(bearing, startBearing);\n        pitch = pitch === undefined ? startPitch : pitch;\n\n        var scale = tr.zoomScale(zoom - startZoom),\n            from = tr.point,\n            to = latlng ? tr.project(latlng).sub(offset.div(scale)) : tr.point,\n            around;\n\n        if (zoom !== startZoom) {\n            around = tr.pointLocation(tr.centerPoint.add(to.sub(from).div(1 - 1 / scale)));\n            this.zooming = true;\n        }\n        if (startBearing !== bearing) this.rotating = true;\n\n        this.fire('movestart');\n\n        this._ease(function (k) {\n            if (zoom !== startZoom) {\n                tr.setZoomAround(interpolate(startZoom, zoom, k), around);\n            } else {\n                tr.center = tr.unproject(from.add(to.sub(from).mult(k)));\n            }\n\n            if (bearing !== startBearing) {\n                tr.bearing = interpolate(startBearing, bearing, k);\n            }\n\n            if (pitch !== startPitch) {\n                tr.pitch = interpolate(startPitch, pitch, k);\n            }\n\n            this.animationLoop.set(300); // text fading\n            this._move(zoom !== startZoom, bearing !== startBearing);\n        }, function() {\n            this.zooming = false;\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Flying animation to a specified location/zoom/bearing with automatic curve\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {Number} zoom\n     * @param {Number} bearing\n     * @param {Object} options\n     * @param {Number} [options.speed=1.2] How fast animation occurs\n     * @param {Number} [options.curve=1.42] How much zooming out occurs during animation\n     * @param {Function} options.easing\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    flyTo: function(latlng, zoom, bearing, options) {\n        this.stop();\n\n        options = util.extend({\n            offset: [0, 0],\n            speed: 1.2,\n            curve: 1.42,\n            easing: util.ease\n        }, options);\n\n        latlng = LatLng.convert(latlng);\n\n        var offset = Point.convert(options.offset),\n            tr = this.transform,\n            startZoom = this.getZoom(),\n            startBearing = this.getBearing();\n\n        zoom = zoom === undefined ? startZoom : zoom;\n        bearing = bearing === undefined ? startBearing : this._normalizeBearing(bearing, startBearing);\n\n        var scale = tr.zoomScale(zoom - startZoom),\n            from = tr.point,\n            to = tr.project(latlng).sub(offset.div(scale));\n\n        if (options.animate === false) {\n            return this.setView(latlng, zoom, bearing, this.getPitch());\n        }\n\n        var startWorldSize = tr.worldSize,\n            rho = options.curve,\n            V = options.speed,\n\n            w0 = Math.max(tr.width, tr.height),\n            w1 = w0 / scale,\n            u1 = to.sub(from).mag(),\n            rho2 = rho * rho;\n\n        function r(i) {\n            var b = (w1 * w1 - w0 * w0 + (i ? -1 : 1) * rho2 * rho2 * u1 * u1) / (2 * (i ? w1 : w0) * rho2 * u1);\n            return Math.log(Math.sqrt(b * b + 1) - b);\n        }\n\n        function sinh(n) { return (Math.exp(n) - Math.exp(-n)) / 2; }\n        function cosh(n) { return (Math.exp(n) + Math.exp(-n)) / 2; }\n        function tanh(n) { return sinh(n) / cosh(n); }\n\n        var r0 = r(0),\n            w = function (s) { return (cosh(r0) / cosh(r0 + rho * s)); },\n            u = function (s) { return w0 * ((cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2) / u1; },\n            S = (r(1) - r0) / rho;\n\n        if (Math.abs(u1) < 0.000001) {\n            if (Math.abs(w0 - w1) < 0.000001) return this;\n\n            var k = w1 < w0 ? -1 : 1;\n            S = Math.abs(Math.log(w1 / w0)) / rho;\n\n            u = function() { return 0; };\n            w = function(s) { return Math.exp(k * rho * s); };\n        }\n\n        options.duration = 1000 * S / V;\n\n        this.zooming = true;\n        if (startBearing !== bearing) this.rotating = true;\n\n        this.fire('movestart');\n\n        this._ease(function (k) {\n            var s = k * S,\n                us = u(s);\n\n            tr.zoom = startZoom + tr.scaleZoom(1 / w(s));\n            tr.center = tr.unproject(from.add(to.sub(from).mult(us)), startWorldSize);\n\n            if (bearing !== startBearing) {\n                tr.bearing = interpolate(startBearing, bearing, k);\n            }\n\n            this.animationLoop.set(300); // text fading\n\n            this._move(true, bearing !== startBearing);\n        }, function() {\n            this.zooming = false;\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    // convert bearing so that it's numerically close to the current one so that it interpolates properly\n    _normalizeBearing: function(bearing, currentBearing) {\n        bearing = util.wrap(bearing, -180, 180);\n        var diff = Math.abs(bearing - currentBearing);\n        if (Math.abs(bearing - 360 - currentBearing) < diff) bearing -= 360;\n        if (Math.abs(bearing + 360 - currentBearing) < diff) bearing += 360;\n        return bearing;\n    },\n\n    _updateEasing: function(duration, zoom, bezier) {\n        var easing;\n\n        if (this.ease) {\n            var ease = this.ease,\n                t = (Date.now() - ease.start) / ease.duration,\n                speed = ease.easing(t + 0.01) - ease.easing(t),\n\n                // Quick hack to make new bezier that is continuous with last\n                x = 0.27 / Math.sqrt(speed * speed + 0.0001) * 0.01,\n                y = Math.sqrt(0.27 * 0.27 - x * x);\n\n            easing = util.bezier(x, y, 0.25, 1);\n        } else {\n            easing = bezier ? util.bezier.apply(util, bezier) : util.ease;\n        }\n\n        // store information on current easing\n        this.ease = {\n            start: (new Date()).getTime(),\n            to: Math.pow(2, zoom),\n            duration: duration,\n            easing: easing\n        };\n\n        return easing;\n    }\n}","path":"js/ui/easings.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/easings.js#L170-L172"},"params":[{"title":"param","description":null,"type":null,"name":"animOptions"}],"returns":[{"title":"returns","description":null,"type":{"type":"NameExpression","name":"this"}}],"name":"zoomIn","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","zoomIn"]},{"description":"Update this map's style and re-render the map.","tags":[{"title":"param","description":"new style","type":{"type":"NameExpression","name":"Object"},"name":"updateStyle"},{"title":"returns","description":"this","type":{"type":"NameExpression","name":"Map"}},{"title":"name","name":"update"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":667,"column":4},"end":{"line":676,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L667-L676"},"params":[{"title":"param","description":"new style","type":{"type":"NameExpression","name":"Object"},"name":"updateStyle"}],"returns":[{"title":"returns","description":"this","type":{"type":"NameExpression","name":"Map"}}],"name":"update","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","update"]},{"description":"Stop current animation","tags":[{"title":"returns","description":null,"type":{"type":"NameExpression","name":"this"}},{"title":"name","name":"stop"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":27,"column":4},"end":{"line":36,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/easings.js","code":"{\n    isEasing: function() {\n        return !!this._abortFn;\n    },\n\n    /**\n     * Stop current animation\n     *\n     * @returns {this}\n     */\n    stop: function() {\n        if (this._abortFn) {\n            this._abortFn.call(this);\n            delete this._abortFn;\n\n            this._finishFn.call(this);\n            delete this._finishFn;\n        }\n        return this;\n    },\n\n    _ease: function(frame, finish, options) {\n        this._finishFn = finish;\n        this._abortFn = browser.timed(function (t) {\n            frame.call(this, options.easing(t));\n            if (t === 1) {\n                delete this._abortFn;\n                this._finishFn.call(this);\n                delete this._finishFn;\n            }\n        }, options.animate === false ? 0 : options.duration, this);\n    },\n\n    /**\n     * Pan by a certain number of pixels\n     *\n     * @param {Array} offset [x, y]\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    panBy: function(offset, options) {\n        this.panTo(this.transform.center, util.extend({offset: Point.convert(offset).mult(-1)}, options));\n        return this;\n    },\n\n    /**\n     * Pan to a certain location with easing\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    panTo: function(latlng, options) {\n        this.stop();\n\n        latlng = LatLng.convert(latlng);\n\n        options = util.extend({\n            duration: 500,\n            easing: util.ease,\n            offset: [0, 0]\n        }, options);\n\n        var tr = this.transform,\n            offset = Point.convert(options.offset).rotate(-tr.angle),\n            from = tr.point,\n            to = tr.project(latlng).sub(offset);\n\n        if (!options.noMoveStart) {\n            this.fire('movestart');\n        }\n\n        this._ease(function(k) {\n            tr.center = tr.unproject(from.add(to.sub(from).mult(k)));\n            this._move();\n        }, function() {\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Zooms to a certain zoom level with easing.\n     *\n     * @param {Number} zoom\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomTo: function(zoom, options) {\n        this.stop();\n\n        options = util.extend({\n            duration: 500\n        }, options);\n\n        options.easing = this._updateEasing(options.duration, zoom, options.easing);\n\n        var tr = this.transform,\n            around = tr.center,\n            startZoom = tr.zoom;\n\n        if (options.around) {\n            around = LatLng.convert(options.around);\n        } else if (options.offset) {\n            around = tr.pointLocation(tr.centerPoint.add(Point.convert(options.offset)));\n        }\n\n        if (options.animate === false) options.duration = 0;\n\n        if (!this.zooming) {\n            this.zooming = true;\n            this.fire('movestart');\n        }\n\n        this._ease(function(k) {\n            tr.setZoomAround(interpolate(startZoom, zoom, k), around);\n            this.animationLoop.set(300); // text fading\n            this._move(true);\n        }, function() {\n            this.ease = null;\n            if (options.duration >= 200) {\n                this.zooming = false;\n                this.fire('moveend');\n            }\n        }, options);\n\n        if (options.duration < 200) {\n            clearTimeout(this._onZoomEnd);\n            this._onZoomEnd = setTimeout(function() {\n                this.zooming = false;\n                this._rerender();\n                this.fire('moveend');\n            }.bind(this), 200);\n        }\n\n        return this;\n    },\n\n    /**\n     * Zoom in by 1 level\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomIn: function(options) {\n        this.zoomTo(this.getZoom() + 1, options);\n    },\n\n    /**\n     * Zoom out by 1 level\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomOut: function(options) {\n        this.zoomTo(this.getZoom() - 1, options);\n    },\n\n    /**\n     * Rotate bearing by a certain number of degrees with easing\n     *\n     * @param {Number} bearing\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    rotateTo: function(bearing, options) {\n        this.stop();\n\n        options = util.extend({\n            duration: 500,\n            easing: util.ease\n        }, options);\n\n        var tr = this.transform,\n            start = this.getBearing(),\n            around = tr.center;\n\n        if (options.around) {\n            around = LatLng.convert(options.around);\n        } else if (options.offset) {\n            around = tr.pointLocation(tr.centerPoint.add(Point.convert(options.offset)));\n        }\n\n        bearing = this._normalizeBearing(bearing, start);\n\n        this.rotating = true;\n        this.fire('movestart');\n\n        this._ease(function(k) {\n            tr.setBearingAround(interpolate(start, bearing, k), around);\n            this._move(false, true);\n        }, function() {\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Sets map bearing to 0 (north) with easing\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    resetNorth: function(options) {\n        return this.rotateTo(0, util.extend({duration: 1000}, options));\n    },\n\n    /**\n     * Zoom to contain certain geographical bounds\n     *\n     * @param {Array} bounds [[minLat, minLng], [maxLat, maxLng]]\n     * @param {Object} options\n     * @param {Number} [options.speed=1.2] How fast animation occurs\n     * @param {Number} [options.curve=1.42] How much zooming out occurs during animation\n     * @param {Function} options.easing\n     * @param {Number} options.padding how much padding there is around the given bounds on each side in pixels\n     * @param {Number} options.maxZoom\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    fitBounds: function(bounds, options) {\n\n        options = util.extend({\n            padding: 0,\n            offset: [0, 0],\n            maxZoom: Infinity\n        }, options);\n\n        bounds = LatLngBounds.convert(bounds);\n\n        var offset = Point.convert(options.offset),\n            tr = this.transform,\n            nw = tr.project(bounds.getNorthWest()),\n            se = tr.project(bounds.getSouthEast()),\n            size = se.sub(nw),\n            center = tr.unproject(nw.add(se).div(2)),\n\n            scaleX = (tr.width - options.padding * 2 - Math.abs(offset.x) * 2) / size.x,\n            scaleY = (tr.height - options.padding * 2 - Math.abs(offset.y) * 2) / size.y,\n\n            zoom = Math.min(tr.scaleZoom(tr.scale * Math.min(scaleX, scaleY)), options.maxZoom);\n\n        return options.linear ?\n            this.easeTo(center, zoom, 0, options) :\n            this.flyTo(center, zoom, 0, options);\n    },\n\n    /**\n     * Easing animation to a specified location/zoom/bearing\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {Number} zoom\n     * @param {Number} bearing\n     * @param {Number} pitch\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    easeTo: function(latlng, zoom, bearing, pitch, options) {\n        this.stop();\n\n        options = util.extend({\n            offset: [0, 0],\n            duration: 500,\n            easing: util.ease\n        }, options);\n\n        var tr = this.transform,\n            offset = Point.convert(options.offset).rotate(-tr.angle),\n            startZoom = this.getZoom(),\n            startBearing = this.getBearing(),\n            startPitch = this.getPitch();\n\n        latlng = LatLng.convert(latlng);\n        zoom = zoom === undefined ? startZoom : zoom;\n        bearing = bearing === undefined ? startBearing : this._normalizeBearing(bearing, startBearing);\n        pitch = pitch === undefined ? startPitch : pitch;\n\n        var scale = tr.zoomScale(zoom - startZoom),\n            from = tr.point,\n            to = latlng ? tr.project(latlng).sub(offset.div(scale)) : tr.point,\n            around;\n\n        if (zoom !== startZoom) {\n            around = tr.pointLocation(tr.centerPoint.add(to.sub(from).div(1 - 1 / scale)));\n            this.zooming = true;\n        }\n        if (startBearing !== bearing) this.rotating = true;\n\n        this.fire('movestart');\n\n        this._ease(function (k) {\n            if (zoom !== startZoom) {\n                tr.setZoomAround(interpolate(startZoom, zoom, k), around);\n            } else {\n                tr.center = tr.unproject(from.add(to.sub(from).mult(k)));\n            }\n\n            if (bearing !== startBearing) {\n                tr.bearing = interpolate(startBearing, bearing, k);\n            }\n\n            if (pitch !== startPitch) {\n                tr.pitch = interpolate(startPitch, pitch, k);\n            }\n\n            this.animationLoop.set(300); // text fading\n            this._move(zoom !== startZoom, bearing !== startBearing);\n        }, function() {\n            this.zooming = false;\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Flying animation to a specified location/zoom/bearing with automatic curve\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {Number} zoom\n     * @param {Number} bearing\n     * @param {Object} options\n     * @param {Number} [options.speed=1.2] How fast animation occurs\n     * @param {Number} [options.curve=1.42] How much zooming out occurs during animation\n     * @param {Function} options.easing\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    flyTo: function(latlng, zoom, bearing, options) {\n        this.stop();\n\n        options = util.extend({\n            offset: [0, 0],\n            speed: 1.2,\n            curve: 1.42,\n            easing: util.ease\n        }, options);\n\n        latlng = LatLng.convert(latlng);\n\n        var offset = Point.convert(options.offset),\n            tr = this.transform,\n            startZoom = this.getZoom(),\n            startBearing = this.getBearing();\n\n        zoom = zoom === undefined ? startZoom : zoom;\n        bearing = bearing === undefined ? startBearing : this._normalizeBearing(bearing, startBearing);\n\n        var scale = tr.zoomScale(zoom - startZoom),\n            from = tr.point,\n            to = tr.project(latlng).sub(offset.div(scale));\n\n        if (options.animate === false) {\n            return this.setView(latlng, zoom, bearing, this.getPitch());\n        }\n\n        var startWorldSize = tr.worldSize,\n            rho = options.curve,\n            V = options.speed,\n\n            w0 = Math.max(tr.width, tr.height),\n            w1 = w0 / scale,\n            u1 = to.sub(from).mag(),\n            rho2 = rho * rho;\n\n        function r(i) {\n            var b = (w1 * w1 - w0 * w0 + (i ? -1 : 1) * rho2 * rho2 * u1 * u1) / (2 * (i ? w1 : w0) * rho2 * u1);\n            return Math.log(Math.sqrt(b * b + 1) - b);\n        }\n\n        function sinh(n) { return (Math.exp(n) - Math.exp(-n)) / 2; }\n        function cosh(n) { return (Math.exp(n) + Math.exp(-n)) / 2; }\n        function tanh(n) { return sinh(n) / cosh(n); }\n\n        var r0 = r(0),\n            w = function (s) { return (cosh(r0) / cosh(r0 + rho * s)); },\n            u = function (s) { return w0 * ((cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2) / u1; },\n            S = (r(1) - r0) / rho;\n\n        if (Math.abs(u1) < 0.000001) {\n            if (Math.abs(w0 - w1) < 0.000001) return this;\n\n            var k = w1 < w0 ? -1 : 1;\n            S = Math.abs(Math.log(w1 / w0)) / rho;\n\n            u = function() { return 0; };\n            w = function(s) { return Math.exp(k * rho * s); };\n        }\n\n        options.duration = 1000 * S / V;\n\n        this.zooming = true;\n        if (startBearing !== bearing) this.rotating = true;\n\n        this.fire('movestart');\n\n        this._ease(function (k) {\n            var s = k * S,\n                us = u(s);\n\n            tr.zoom = startZoom + tr.scaleZoom(1 / w(s));\n            tr.center = tr.unproject(from.add(to.sub(from).mult(us)), startWorldSize);\n\n            if (bearing !== startBearing) {\n                tr.bearing = interpolate(startBearing, bearing, k);\n            }\n\n            this.animationLoop.set(300); // text fading\n\n            this._move(true, bearing !== startBearing);\n        }, function() {\n            this.zooming = false;\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    // convert bearing so that it's numerically close to the current one so that it interpolates properly\n    _normalizeBearing: function(bearing, currentBearing) {\n        bearing = util.wrap(bearing, -180, 180);\n        var diff = Math.abs(bearing - currentBearing);\n        if (Math.abs(bearing - 360 - currentBearing) < diff) bearing -= 360;\n        if (Math.abs(bearing + 360 - currentBearing) < diff) bearing += 360;\n        return bearing;\n    },\n\n    _updateEasing: function(duration, zoom, bezier) {\n        var easing;\n\n        if (this.ease) {\n            var ease = this.ease,\n                t = (Date.now() - ease.start) / ease.duration,\n                speed = ease.easing(t + 0.01) - ease.easing(t),\n\n                // Quick hack to make new bezier that is continuous with last\n                x = 0.27 / Math.sqrt(speed * speed + 0.0001) * 0.01,\n                y = Math.sqrt(0.27 * 0.27 - x * x);\n\n            easing = util.bezier(x, y, 0.25, 1);\n        } else {\n            easing = bezier ? util.bezier.apply(util, bezier) : util.ease;\n        }\n\n        // store information on current easing\n        this.ease = {\n            start: (new Date()).getTime(),\n            to: Math.pow(2, zoom),\n            duration: duration,\n            easing: easing\n        };\n\n        return easing;\n    }\n}","path":"js/ui/easings.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/easings.js#L27-L36"},"returns":[{"title":"returns","description":null,"type":{"type":"NameExpression","name":"this"}}],"name":"stop","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","stop"]},{"description":"Sets a map position","tags":[{"title":"param","description":"Latitude and longitude (passed as `[lat, lng]`)","type":{"type":"NameExpression","name":"Array"},"name":"center"},{"title":"param","description":"Map zoom level","type":{"type":"NameExpression","name":"number"},"name":"zoom"},{"title":"param","description":"Map rotation bearing in degrees counter-clockwise from north","type":{"type":"NameExpression","name":"number"},"name":"bearing"},{"title":"param","description":"The angle at which the camera is looking at the ground","type":{"type":"NameExpression","name":"number"},"name":"pitch"},{"title":"fires","description":"movestart"},{"title":"fires","description":"moveend"},{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}},{"title":"name","name":"setView"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":130,"column":4},"end":{"line":147,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L130-L147"},"params":[{"title":"param","description":"Latitude and longitude (passed as `[lat, lng]`)","type":{"type":"NameExpression","name":"Array"},"name":"center"},{"title":"param","description":"Map zoom level","type":{"type":"NameExpression","name":"number"},"name":"zoom"},{"title":"param","description":"Map rotation bearing in degrees counter-clockwise from north","type":{"type":"NameExpression","name":"number"},"name":"bearing"},{"title":"param","description":"The angle at which the camera is looking at the ground","type":{"type":"NameExpression","name":"number"},"name":"pitch"}],"returns":[{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}}],"name":"setView","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","setView"]},{"description":"Sets a map zoom","tags":[{"title":"param","description":"Map zoom level","type":{"type":"NameExpression","name":"number"},"name":"zoom"},{"title":"fires","description":"movestart"},{"title":"fires","description":"moveend"},{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}},{"title":"name","name":"setZoom"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":169,"column":4},"end":{"line":171,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L169-L171"},"params":[{"title":"param","description":"Map zoom level","type":{"type":"NameExpression","name":"number"},"name":"zoom"}],"returns":[{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}}],"name":"setZoom","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","setZoom"]},{"description":"Get geographical coordinates given pixel coordinates","tags":[{"title":"param","description":"[x, y] pixel coordinates","type":{"type":"TypeApplication","expression":{"type":"NameExpression","name":"Array"},"applications":[{"type":"NameExpression","name":"number"}]},"name":"point"},{"title":"returns","description":null,"type":{"type":"NameExpression","name":"LatLng"}},{"title":"name","name":"unproject"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":344,"column":4},"end":{"line":346,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L344-L346"},"params":[{"title":"param","description":"[x, y] pixel coordinates","type":{"type":"TypeApplication","expression":{"type":"NameExpression","name":"Array"},"applications":[{"type":"NameExpression","name":"number"}]},"name":"point"}],"returns":[{"title":"returns","description":null,"type":{"type":"NameExpression","name":"LatLng"}}],"name":"unproject","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","unproject"]},{"description":"Set the value of a layout property in a given style layer.","tags":[{"title":"param","description":"ID of a layer","type":{"type":"NameExpression","name":"string"},"name":"layer"},{"title":"param","description":"name of a layout property","type":{"type":"NameExpression","name":"string"},"name":"name"},{"title":"param","description":"value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)","type":{"type":"AllLiteral"},"name":"value"},{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}},{"title":"name","name":"setLayoutProperty"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":552,"column":4},"end":{"line":555,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L552-L555"},"params":[{"title":"param","description":"ID of a layer","type":{"type":"NameExpression","name":"string"},"name":"layer"},{"title":"param","description":"name of a layout property","type":{"type":"NameExpression","name":"string"},"name":"name"},{"title":"param","description":"value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)","type":{"type":"AllLiteral"},"name":"value"}],"returns":[{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}}],"name":"setLayoutProperty","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","setLayoutProperty"]},{"description":"Sets a map rotation","tags":[{"title":"param","description":"Map rotation bearing in degrees counter-clockwise from north","type":{"type":"NameExpression","name":"number"},"name":"bearing"},{"title":"fires","description":"movestart"},{"title":"fires","description":"moveend"},{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}},{"title":"name","name":"setBearing"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":181,"column":4},"end":{"line":183,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L181-L183"},"params":[{"title":"param","description":"Map rotation bearing in degrees counter-clockwise from north","type":{"type":"NameExpression","name":"number"},"name":"bearing"}],"returns":[{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}}],"name":"setBearing","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","setBearing"]},{"description":"Set the value of a paint property in a given style layer.","tags":[{"title":"param","description":"ID of a layer","type":{"type":"NameExpression","name":"string"},"name":"layer"},{"title":"param","description":"name of a paint property","type":{"type":"NameExpression","name":"string"},"name":"name"},{"title":"param","description":"value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)","type":{"type":"AllLiteral"},"name":"value"},{"title":"param","description":"optional class specifier for the property","type":{"type":"OptionalType","expression":{"type":"NameExpression","name":"string"}},"name":"klass"},{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}},{"title":"name","name":"setPaintProperty"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":525,"column":4},"end":{"line":530,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L525-L530"},"params":[{"title":"param","description":"ID of a layer","type":{"type":"NameExpression","name":"string"},"name":"layer"},{"title":"param","description":"name of a paint property","type":{"type":"NameExpression","name":"string"},"name":"name"},{"title":"param","description":"value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)","type":{"type":"AllLiteral"},"name":"value"},{"title":"param","description":"optional class specifier for the property","type":{"type":"OptionalType","expression":{"type":"NameExpression","name":"string"}},"name":"klass"}],"returns":[{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}}],"name":"setPaintProperty","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","setPaintProperty"]},{"description":"Sets a map location","tags":[{"title":"param","description":"Latitude and longitude (passed as `[lat, lng]`)","type":{"type":"NameExpression","name":"Array"},"name":"center"},{"title":"fires","description":"movestart"},{"title":"fires","description":"moveend"},{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}},{"title":"name","name":"setCenter"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":157,"column":4},"end":{"line":159,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L157-L159"},"params":[{"title":"param","description":"Latitude and longitude (passed as `[lat, lng]`)","type":{"type":"NameExpression","name":"Array"},"name":"center"}],"returns":[{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}}],"name":"setCenter","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","setCenter"]},{"description":"Set the filter for a given style layer.","tags":[{"title":"param","description":"ID of a layer","type":{"type":"NameExpression","name":"string"},"name":"layer"},{"title":"param","description":"filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)","type":{"type":"NameExpression","name":"Array"},"name":"filter"},{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}},{"title":"name","name":"setFilter"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":501,"column":4},"end":{"line":504,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L501-L504"},"params":[{"title":"param","description":"ID of a layer","type":{"type":"NameExpression","name":"string"},"name":"layer"},{"title":"param","description":"filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)","type":{"type":"NameExpression","name":"Array"},"name":"filter"}],"returns":[{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}}],"name":"setFilter","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","setFilter"]},{"description":"Helper method to add more than one class","tags":[{"title":"param","description":"An array of class names","type":{"type":"TypeApplication","expression":{"type":"NameExpression","name":"Array"},"applications":[{"type":"NameExpression","name":"string"}]},"name":"klasses"},{"title":"param","description":null,"type":{"type":"NameExpression","name":"styleOptions"},"name":"options"},{"title":"fires","description":"change"},{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}},{"title":"name","name":"setClasses"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":262,"column":4},"end":{"line":268,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L262-L268"},"params":[{"title":"param","description":"An array of class names","type":{"type":"TypeApplication","expression":{"type":"NameExpression","name":"Array"},"applications":[{"type":"NameExpression","name":"string"}]},"name":"klasses"},{"title":"param","description":null,"type":{"type":"NameExpression","name":"styleOptions"},"name":"options"}],"returns":[{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}}],"name":"setClasses","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","setClasses"]},{"description":"Rotate bearing by a certain number of degrees with easing","tags":[{"title":"param","description":null,"type":{"type":"NameExpression","name":"Number"},"name":"bearing"},{"title":"param","description":null,"type":null,"name":"animOptions"},{"title":"fires","description":"movestart"},{"title":"fires","description":"moveend"},{"title":"returns","description":null,"type":{"type":"NameExpression","name":"this"}},{"title":"name","name":"rotateTo"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":195,"column":4},"end":{"line":227,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/easings.js","code":"{\n    isEasing: function() {\n        return !!this._abortFn;\n    },\n\n    /**\n     * Stop current animation\n     *\n     * @returns {this}\n     */\n    stop: function() {\n        if (this._abortFn) {\n            this._abortFn.call(this);\n            delete this._abortFn;\n\n            this._finishFn.call(this);\n            delete this._finishFn;\n        }\n        return this;\n    },\n\n    _ease: function(frame, finish, options) {\n        this._finishFn = finish;\n        this._abortFn = browser.timed(function (t) {\n            frame.call(this, options.easing(t));\n            if (t === 1) {\n                delete this._abortFn;\n                this._finishFn.call(this);\n                delete this._finishFn;\n            }\n        }, options.animate === false ? 0 : options.duration, this);\n    },\n\n    /**\n     * Pan by a certain number of pixels\n     *\n     * @param {Array} offset [x, y]\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    panBy: function(offset, options) {\n        this.panTo(this.transform.center, util.extend({offset: Point.convert(offset).mult(-1)}, options));\n        return this;\n    },\n\n    /**\n     * Pan to a certain location with easing\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    panTo: function(latlng, options) {\n        this.stop();\n\n        latlng = LatLng.convert(latlng);\n\n        options = util.extend({\n            duration: 500,\n            easing: util.ease,\n            offset: [0, 0]\n        }, options);\n\n        var tr = this.transform,\n            offset = Point.convert(options.offset).rotate(-tr.angle),\n            from = tr.point,\n            to = tr.project(latlng).sub(offset);\n\n        if (!options.noMoveStart) {\n            this.fire('movestart');\n        }\n\n        this._ease(function(k) {\n            tr.center = tr.unproject(from.add(to.sub(from).mult(k)));\n            this._move();\n        }, function() {\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Zooms to a certain zoom level with easing.\n     *\n     * @param {Number} zoom\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomTo: function(zoom, options) {\n        this.stop();\n\n        options = util.extend({\n            duration: 500\n        }, options);\n\n        options.easing = this._updateEasing(options.duration, zoom, options.easing);\n\n        var tr = this.transform,\n            around = tr.center,\n            startZoom = tr.zoom;\n\n        if (options.around) {\n            around = LatLng.convert(options.around);\n        } else if (options.offset) {\n            around = tr.pointLocation(tr.centerPoint.add(Point.convert(options.offset)));\n        }\n\n        if (options.animate === false) options.duration = 0;\n\n        if (!this.zooming) {\n            this.zooming = true;\n            this.fire('movestart');\n        }\n\n        this._ease(function(k) {\n            tr.setZoomAround(interpolate(startZoom, zoom, k), around);\n            this.animationLoop.set(300); // text fading\n            this._move(true);\n        }, function() {\n            this.ease = null;\n            if (options.duration >= 200) {\n                this.zooming = false;\n                this.fire('moveend');\n            }\n        }, options);\n\n        if (options.duration < 200) {\n            clearTimeout(this._onZoomEnd);\n            this._onZoomEnd = setTimeout(function() {\n                this.zooming = false;\n                this._rerender();\n                this.fire('moveend');\n            }.bind(this), 200);\n        }\n\n        return this;\n    },\n\n    /**\n     * Zoom in by 1 level\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomIn: function(options) {\n        this.zoomTo(this.getZoom() + 1, options);\n    },\n\n    /**\n     * Zoom out by 1 level\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomOut: function(options) {\n        this.zoomTo(this.getZoom() - 1, options);\n    },\n\n    /**\n     * Rotate bearing by a certain number of degrees with easing\n     *\n     * @param {Number} bearing\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    rotateTo: function(bearing, options) {\n        this.stop();\n\n        options = util.extend({\n            duration: 500,\n            easing: util.ease\n        }, options);\n\n        var tr = this.transform,\n            start = this.getBearing(),\n            around = tr.center;\n\n        if (options.around) {\n            around = LatLng.convert(options.around);\n        } else if (options.offset) {\n            around = tr.pointLocation(tr.centerPoint.add(Point.convert(options.offset)));\n        }\n\n        bearing = this._normalizeBearing(bearing, start);\n\n        this.rotating = true;\n        this.fire('movestart');\n\n        this._ease(function(k) {\n            tr.setBearingAround(interpolate(start, bearing, k), around);\n            this._move(false, true);\n        }, function() {\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Sets map bearing to 0 (north) with easing\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    resetNorth: function(options) {\n        return this.rotateTo(0, util.extend({duration: 1000}, options));\n    },\n\n    /**\n     * Zoom to contain certain geographical bounds\n     *\n     * @param {Array} bounds [[minLat, minLng], [maxLat, maxLng]]\n     * @param {Object} options\n     * @param {Number} [options.speed=1.2] How fast animation occurs\n     * @param {Number} [options.curve=1.42] How much zooming out occurs during animation\n     * @param {Function} options.easing\n     * @param {Number} options.padding how much padding there is around the given bounds on each side in pixels\n     * @param {Number} options.maxZoom\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    fitBounds: function(bounds, options) {\n\n        options = util.extend({\n            padding: 0,\n            offset: [0, 0],\n            maxZoom: Infinity\n        }, options);\n\n        bounds = LatLngBounds.convert(bounds);\n\n        var offset = Point.convert(options.offset),\n            tr = this.transform,\n            nw = tr.project(bounds.getNorthWest()),\n            se = tr.project(bounds.getSouthEast()),\n            size = se.sub(nw),\n            center = tr.unproject(nw.add(se).div(2)),\n\n            scaleX = (tr.width - options.padding * 2 - Math.abs(offset.x) * 2) / size.x,\n            scaleY = (tr.height - options.padding * 2 - Math.abs(offset.y) * 2) / size.y,\n\n            zoom = Math.min(tr.scaleZoom(tr.scale * Math.min(scaleX, scaleY)), options.maxZoom);\n\n        return options.linear ?\n            this.easeTo(center, zoom, 0, options) :\n            this.flyTo(center, zoom, 0, options);\n    },\n\n    /**\n     * Easing animation to a specified location/zoom/bearing\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {Number} zoom\n     * @param {Number} bearing\n     * @param {Number} pitch\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    easeTo: function(latlng, zoom, bearing, pitch, options) {\n        this.stop();\n\n        options = util.extend({\n            offset: [0, 0],\n            duration: 500,\n            easing: util.ease\n        }, options);\n\n        var tr = this.transform,\n            offset = Point.convert(options.offset).rotate(-tr.angle),\n            startZoom = this.getZoom(),\n            startBearing = this.getBearing(),\n            startPitch = this.getPitch();\n\n        latlng = LatLng.convert(latlng);\n        zoom = zoom === undefined ? startZoom : zoom;\n        bearing = bearing === undefined ? startBearing : this._normalizeBearing(bearing, startBearing);\n        pitch = pitch === undefined ? startPitch : pitch;\n\n        var scale = tr.zoomScale(zoom - startZoom),\n            from = tr.point,\n            to = latlng ? tr.project(latlng).sub(offset.div(scale)) : tr.point,\n            around;\n\n        if (zoom !== startZoom) {\n            around = tr.pointLocation(tr.centerPoint.add(to.sub(from).div(1 - 1 / scale)));\n            this.zooming = true;\n        }\n        if (startBearing !== bearing) this.rotating = true;\n\n        this.fire('movestart');\n\n        this._ease(function (k) {\n            if (zoom !== startZoom) {\n                tr.setZoomAround(interpolate(startZoom, zoom, k), around);\n            } else {\n                tr.center = tr.unproject(from.add(to.sub(from).mult(k)));\n            }\n\n            if (bearing !== startBearing) {\n                tr.bearing = interpolate(startBearing, bearing, k);\n            }\n\n            if (pitch !== startPitch) {\n                tr.pitch = interpolate(startPitch, pitch, k);\n            }\n\n            this.animationLoop.set(300); // text fading\n            this._move(zoom !== startZoom, bearing !== startBearing);\n        }, function() {\n            this.zooming = false;\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Flying animation to a specified location/zoom/bearing with automatic curve\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {Number} zoom\n     * @param {Number} bearing\n     * @param {Object} options\n     * @param {Number} [options.speed=1.2] How fast animation occurs\n     * @param {Number} [options.curve=1.42] How much zooming out occurs during animation\n     * @param {Function} options.easing\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    flyTo: function(latlng, zoom, bearing, options) {\n        this.stop();\n\n        options = util.extend({\n            offset: [0, 0],\n            speed: 1.2,\n            curve: 1.42,\n            easing: util.ease\n        }, options);\n\n        latlng = LatLng.convert(latlng);\n\n        var offset = Point.convert(options.offset),\n            tr = this.transform,\n            startZoom = this.getZoom(),\n            startBearing = this.getBearing();\n\n        zoom = zoom === undefined ? startZoom : zoom;\n        bearing = bearing === undefined ? startBearing : this._normalizeBearing(bearing, startBearing);\n\n        var scale = tr.zoomScale(zoom - startZoom),\n            from = tr.point,\n            to = tr.project(latlng).sub(offset.div(scale));\n\n        if (options.animate === false) {\n            return this.setView(latlng, zoom, bearing, this.getPitch());\n        }\n\n        var startWorldSize = tr.worldSize,\n            rho = options.curve,\n            V = options.speed,\n\n            w0 = Math.max(tr.width, tr.height),\n            w1 = w0 / scale,\n            u1 = to.sub(from).mag(),\n            rho2 = rho * rho;\n\n        function r(i) {\n            var b = (w1 * w1 - w0 * w0 + (i ? -1 : 1) * rho2 * rho2 * u1 * u1) / (2 * (i ? w1 : w0) * rho2 * u1);\n            return Math.log(Math.sqrt(b * b + 1) - b);\n        }\n\n        function sinh(n) { return (Math.exp(n) - Math.exp(-n)) / 2; }\n        function cosh(n) { return (Math.exp(n) + Math.exp(-n)) / 2; }\n        function tanh(n) { return sinh(n) / cosh(n); }\n\n        var r0 = r(0),\n            w = function (s) { return (cosh(r0) / cosh(r0 + rho * s)); },\n            u = function (s) { return w0 * ((cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2) / u1; },\n            S = (r(1) - r0) / rho;\n\n        if (Math.abs(u1) < 0.000001) {\n            if (Math.abs(w0 - w1) < 0.000001) return this;\n\n            var k = w1 < w0 ? -1 : 1;\n            S = Math.abs(Math.log(w1 / w0)) / rho;\n\n            u = function() { return 0; };\n            w = function(s) { return Math.exp(k * rho * s); };\n        }\n\n        options.duration = 1000 * S / V;\n\n        this.zooming = true;\n        if (startBearing !== bearing) this.rotating = true;\n\n        this.fire('movestart');\n\n        this._ease(function (k) {\n            var s = k * S,\n                us = u(s);\n\n            tr.zoom = startZoom + tr.scaleZoom(1 / w(s));\n            tr.center = tr.unproject(from.add(to.sub(from).mult(us)), startWorldSize);\n\n            if (bearing !== startBearing) {\n                tr.bearing = interpolate(startBearing, bearing, k);\n            }\n\n            this.animationLoop.set(300); // text fading\n\n            this._move(true, bearing !== startBearing);\n        }, function() {\n            this.zooming = false;\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    // convert bearing so that it's numerically close to the current one so that it interpolates properly\n    _normalizeBearing: function(bearing, currentBearing) {\n        bearing = util.wrap(bearing, -180, 180);\n        var diff = Math.abs(bearing - currentBearing);\n        if (Math.abs(bearing - 360 - currentBearing) < diff) bearing -= 360;\n        if (Math.abs(bearing + 360 - currentBearing) < diff) bearing += 360;\n        return bearing;\n    },\n\n    _updateEasing: function(duration, zoom, bezier) {\n        var easing;\n\n        if (this.ease) {\n            var ease = this.ease,\n                t = (Date.now() - ease.start) / ease.duration,\n                speed = ease.easing(t + 0.01) - ease.easing(t),\n\n                // Quick hack to make new bezier that is continuous with last\n                x = 0.27 / Math.sqrt(speed * speed + 0.0001) * 0.01,\n                y = Math.sqrt(0.27 * 0.27 - x * x);\n\n            easing = util.bezier(x, y, 0.25, 1);\n        } else {\n            easing = bezier ? util.bezier.apply(util, bezier) : util.ease;\n        }\n\n        // store information on current easing\n        this.ease = {\n            start: (new Date()).getTime(),\n            to: Math.pow(2, zoom),\n            duration: duration,\n            easing: easing\n        };\n\n        return easing;\n    }\n}","path":"js/ui/easings.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/easings.js#L195-L227"},"params":[{"title":"param","description":null,"type":{"type":"NameExpression","name":"Number"},"name":"bearing"},{"title":"param","description":null,"type":null,"name":"animOptions"}],"returns":[{"title":"returns","description":null,"type":{"type":"NameExpression","name":"this"}}],"name":"rotateTo","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","rotateTo"]},{"description":"Replaces the map's style object","tags":[{"title":"param","description":"A style object formatted as JSON","type":{"type":"NameExpression","name":"Object"},"name":"style"},{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}},{"title":"name","name":"setStyle"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":376,"column":4},"end":{"line":428,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L376-L428"},"params":[{"title":"param","description":"A style object formatted as JSON","type":{"type":"NameExpression","name":"Object"},"name":"style"}],"returns":[{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}}],"name":"setStyle","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","setStyle"]},{"description":"Remove an existing source from the map style.","tags":[{"title":"param","description":"ID of the source to remove","type":{"type":"NameExpression","name":"string"},"name":"id"},{"title":"fires","description":"source.remove"},{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}},{"title":"name","name":"removeSource"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":451,"column":4},"end":{"line":454,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L451-L454"},"params":[{"title":"param","description":"ID of the source to remove","type":{"type":"NameExpression","name":"string"},"name":"id"}],"returns":[{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}}],"name":"removeSource","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","removeSource"]},{"description":"Return the style source object with the given `id`.","tags":[{"title":"param","description":"source ID","type":{"type":"NameExpression","name":"string"},"name":"id"},{"title":"returns","description":null,"type":{"type":"NameExpression","name":"Object"}},{"title":"name","name":"getSource"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":462,"column":4},"end":{"line":464,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L462-L464"},"params":[{"title":"param","description":"source ID","type":{"type":"NameExpression","name":"string"},"name":"id"}],"returns":[{"title":"returns","description":null,"type":{"type":"NameExpression","name":"Object"}}],"name":"getSource","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","getSource"]},{"description":"Get pixel coordinates (relative to map container) given a geographical location","tags":[{"title":"param","description":null,"type":{"type":"NameExpression","name":"LatLng"},"name":"latlng"},{"title":"returns","description":"`x` and `y` coordinates","type":{"type":"NameExpression","name":"Object"}},{"title":"name","name":"project"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":334,"column":4},"end":{"line":336,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L334-L336"},"params":[{"title":"param","description":null,"type":{"type":"NameExpression","name":"LatLng"},"name":"latlng"}],"returns":[{"title":"returns","description":"`x` and `y` coordinates","type":{"type":"NameExpression","name":"Object"}}],"name":"project","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","project"]},{"description":"Check whether a style class is active","tags":[{"title":"param","description":"Name of style class","type":{"type":"NameExpression","name":"string"},"name":"klass"},{"title":"returns","description":null,"type":{"type":"NameExpression","name":"boolean"}},{"title":"name","name":"hasClass"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":276,"column":4},"end":{"line":278,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L276-L278"},"params":[{"title":"param","description":"Name of style class","type":{"type":"NameExpression","name":"string"},"name":"klass"}],"returns":[{"title":"returns","description":null,"type":{"type":"NameExpression","name":"boolean"}}],"name":"hasClass","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","hasClass"]},{"description":"Remove the layer with the given `id` from the map. Any layers which refer to the\nspecified layer via a `ref` property are also removed.","tags":[{"title":"param","description":null,"type":{"type":"NameExpression","name":"string"},"name":"id"},{"title":"fires","description":"layer.remove"},{"title":"returns","description":"this","type":{"type":"NameExpression","name":"Map"}},{"title":"name","name":"removeLayer"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":488,"column":4},"end":{"line":492,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L488-L492"},"params":[{"title":"param","description":null,"type":{"type":"NameExpression","name":"string"},"name":"id"}],"returns":[{"title":"returns","description":"this","type":{"type":"NameExpression","name":"Map"}}],"name":"removeLayer","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","removeLayer"]},{"description":"Removes a style class from a map","tags":[{"title":"param","description":"name of style class","type":{"type":"NameExpression","name":"string"},"name":"klass"},{"title":"param","description":null,"type":{"type":"NameExpression","name":"styleOptions"},"name":"options"},{"title":"fires","description":"change"},{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}},{"title":"name","name":"removeClass"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":248,"column":4},"end":{"line":252,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L248-L252"},"params":[{"title":"param","description":"name of style class","type":{"type":"NameExpression","name":"string"},"name":"klass"},{"title":"param","description":null,"type":{"type":"NameExpression","name":"styleOptions"},"name":"options"}],"returns":[{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}}],"name":"removeClass","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","removeClass"]},{"description":"Get the current angle in degrees","tags":[{"title":"returns","description":null,"type":{"type":"NameExpression","name":"number"}},{"title":"name","name":"getPitch"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":219,"column":4},"end":{"line":219,"column":57}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L219-L219"},"returns":[{"title":"returns","description":null,"type":{"type":"NameExpression","name":"number"}}],"name":"getPitch","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","getPitch"]},{"description":"Get the value of a paint property in a given style layer.","tags":[{"title":"param","description":"ID of a layer","type":{"type":"NameExpression","name":"string"},"name":"layer"},{"title":"param","description":"name of a paint property","type":{"type":"NameExpression","name":"string"},"name":"name"},{"title":"param","description":"optional class specifier for the property","type":{"type":"OptionalType","expression":{"type":"NameExpression","name":"string"}},"name":"klass"},{"title":"returns","description":"value for the paint propery","type":{"type":"AllLiteral"}},{"title":"name","name":"getPaintProperty"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":540,"column":4},"end":{"line":542,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L540-L542"},"params":[{"title":"param","description":"ID of a layer","type":{"type":"NameExpression","name":"string"},"name":"layer"},{"title":"param","description":"name of a paint property","type":{"type":"NameExpression","name":"string"},"name":"name"},{"title":"param","description":"optional class specifier for the property","type":{"type":"OptionalType","expression":{"type":"NameExpression","name":"string"}},"name":"klass"}],"returns":[{"title":"returns","description":"value for the paint propery","type":{"type":"AllLiteral"}}],"name":"getPaintProperty","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","getPaintProperty"]},{"description":"Get the current zoom","tags":[{"title":"returns","description":null,"type":{"type":"NameExpression","name":"number"}},{"title":"name","name":"getZoom"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":207,"column":4},"end":{"line":207,"column":55}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L207-L207"},"returns":[{"title":"returns","description":null,"type":{"type":"NameExpression","name":"number"}}],"name":"getZoom","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","getZoom"]},{"description":"Pan by a certain number of pixels","tags":[{"title":"param","description":"[x, y]","type":{"type":"NameExpression","name":"Array"},"name":"offset"},{"title":"param","description":null,"type":null,"name":"animOptions"},{"title":"fires","description":"movestart"},{"title":"fires","description":"moveend"},{"title":"returns","description":null,"type":{"type":"NameExpression","name":"this"}},{"title":"name","name":"panBy"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":59,"column":4},"end":{"line":62,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/easings.js","code":"{\n    isEasing: function() {\n        return !!this._abortFn;\n    },\n\n    /**\n     * Stop current animation\n     *\n     * @returns {this}\n     */\n    stop: function() {\n        if (this._abortFn) {\n            this._abortFn.call(this);\n            delete this._abortFn;\n\n            this._finishFn.call(this);\n            delete this._finishFn;\n        }\n        return this;\n    },\n\n    _ease: function(frame, finish, options) {\n        this._finishFn = finish;\n        this._abortFn = browser.timed(function (t) {\n            frame.call(this, options.easing(t));\n            if (t === 1) {\n                delete this._abortFn;\n                this._finishFn.call(this);\n                delete this._finishFn;\n            }\n        }, options.animate === false ? 0 : options.duration, this);\n    },\n\n    /**\n     * Pan by a certain number of pixels\n     *\n     * @param {Array} offset [x, y]\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    panBy: function(offset, options) {\n        this.panTo(this.transform.center, util.extend({offset: Point.convert(offset).mult(-1)}, options));\n        return this;\n    },\n\n    /**\n     * Pan to a certain location with easing\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    panTo: function(latlng, options) {\n        this.stop();\n\n        latlng = LatLng.convert(latlng);\n\n        options = util.extend({\n            duration: 500,\n            easing: util.ease,\n            offset: [0, 0]\n        }, options);\n\n        var tr = this.transform,\n            offset = Point.convert(options.offset).rotate(-tr.angle),\n            from = tr.point,\n            to = tr.project(latlng).sub(offset);\n\n        if (!options.noMoveStart) {\n            this.fire('movestart');\n        }\n\n        this._ease(function(k) {\n            tr.center = tr.unproject(from.add(to.sub(from).mult(k)));\n            this._move();\n        }, function() {\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Zooms to a certain zoom level with easing.\n     *\n     * @param {Number} zoom\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomTo: function(zoom, options) {\n        this.stop();\n\n        options = util.extend({\n            duration: 500\n        }, options);\n\n        options.easing = this._updateEasing(options.duration, zoom, options.easing);\n\n        var tr = this.transform,\n            around = tr.center,\n            startZoom = tr.zoom;\n\n        if (options.around) {\n            around = LatLng.convert(options.around);\n        } else if (options.offset) {\n            around = tr.pointLocation(tr.centerPoint.add(Point.convert(options.offset)));\n        }\n\n        if (options.animate === false) options.duration = 0;\n\n        if (!this.zooming) {\n            this.zooming = true;\n            this.fire('movestart');\n        }\n\n        this._ease(function(k) {\n            tr.setZoomAround(interpolate(startZoom, zoom, k), around);\n            this.animationLoop.set(300); // text fading\n            this._move(true);\n        }, function() {\n            this.ease = null;\n            if (options.duration >= 200) {\n                this.zooming = false;\n                this.fire('moveend');\n            }\n        }, options);\n\n        if (options.duration < 200) {\n            clearTimeout(this._onZoomEnd);\n            this._onZoomEnd = setTimeout(function() {\n                this.zooming = false;\n                this._rerender();\n                this.fire('moveend');\n            }.bind(this), 200);\n        }\n\n        return this;\n    },\n\n    /**\n     * Zoom in by 1 level\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomIn: function(options) {\n        this.zoomTo(this.getZoom() + 1, options);\n    },\n\n    /**\n     * Zoom out by 1 level\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomOut: function(options) {\n        this.zoomTo(this.getZoom() - 1, options);\n    },\n\n    /**\n     * Rotate bearing by a certain number of degrees with easing\n     *\n     * @param {Number} bearing\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    rotateTo: function(bearing, options) {\n        this.stop();\n\n        options = util.extend({\n            duration: 500,\n            easing: util.ease\n        }, options);\n\n        var tr = this.transform,\n            start = this.getBearing(),\n            around = tr.center;\n\n        if (options.around) {\n            around = LatLng.convert(options.around);\n        } else if (options.offset) {\n            around = tr.pointLocation(tr.centerPoint.add(Point.convert(options.offset)));\n        }\n\n        bearing = this._normalizeBearing(bearing, start);\n\n        this.rotating = true;\n        this.fire('movestart');\n\n        this._ease(function(k) {\n            tr.setBearingAround(interpolate(start, bearing, k), around);\n            this._move(false, true);\n        }, function() {\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Sets map bearing to 0 (north) with easing\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    resetNorth: function(options) {\n        return this.rotateTo(0, util.extend({duration: 1000}, options));\n    },\n\n    /**\n     * Zoom to contain certain geographical bounds\n     *\n     * @param {Array} bounds [[minLat, minLng], [maxLat, maxLng]]\n     * @param {Object} options\n     * @param {Number} [options.speed=1.2] How fast animation occurs\n     * @param {Number} [options.curve=1.42] How much zooming out occurs during animation\n     * @param {Function} options.easing\n     * @param {Number} options.padding how much padding there is around the given bounds on each side in pixels\n     * @param {Number} options.maxZoom\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    fitBounds: function(bounds, options) {\n\n        options = util.extend({\n            padding: 0,\n            offset: [0, 0],\n            maxZoom: Infinity\n        }, options);\n\n        bounds = LatLngBounds.convert(bounds);\n\n        var offset = Point.convert(options.offset),\n            tr = this.transform,\n            nw = tr.project(bounds.getNorthWest()),\n            se = tr.project(bounds.getSouthEast()),\n            size = se.sub(nw),\n            center = tr.unproject(nw.add(se).div(2)),\n\n            scaleX = (tr.width - options.padding * 2 - Math.abs(offset.x) * 2) / size.x,\n            scaleY = (tr.height - options.padding * 2 - Math.abs(offset.y) * 2) / size.y,\n\n            zoom = Math.min(tr.scaleZoom(tr.scale * Math.min(scaleX, scaleY)), options.maxZoom);\n\n        return options.linear ?\n            this.easeTo(center, zoom, 0, options) :\n            this.flyTo(center, zoom, 0, options);\n    },\n\n    /**\n     * Easing animation to a specified location/zoom/bearing\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {Number} zoom\n     * @param {Number} bearing\n     * @param {Number} pitch\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    easeTo: function(latlng, zoom, bearing, pitch, options) {\n        this.stop();\n\n        options = util.extend({\n            offset: [0, 0],\n            duration: 500,\n            easing: util.ease\n        }, options);\n\n        var tr = this.transform,\n            offset = Point.convert(options.offset).rotate(-tr.angle),\n            startZoom = this.getZoom(),\n            startBearing = this.getBearing(),\n            startPitch = this.getPitch();\n\n        latlng = LatLng.convert(latlng);\n        zoom = zoom === undefined ? startZoom : zoom;\n        bearing = bearing === undefined ? startBearing : this._normalizeBearing(bearing, startBearing);\n        pitch = pitch === undefined ? startPitch : pitch;\n\n        var scale = tr.zoomScale(zoom - startZoom),\n            from = tr.point,\n            to = latlng ? tr.project(latlng).sub(offset.div(scale)) : tr.point,\n            around;\n\n        if (zoom !== startZoom) {\n            around = tr.pointLocation(tr.centerPoint.add(to.sub(from).div(1 - 1 / scale)));\n            this.zooming = true;\n        }\n        if (startBearing !== bearing) this.rotating = true;\n\n        this.fire('movestart');\n\n        this._ease(function (k) {\n            if (zoom !== startZoom) {\n                tr.setZoomAround(interpolate(startZoom, zoom, k), around);\n            } else {\n                tr.center = tr.unproject(from.add(to.sub(from).mult(k)));\n            }\n\n            if (bearing !== startBearing) {\n                tr.bearing = interpolate(startBearing, bearing, k);\n            }\n\n            if (pitch !== startPitch) {\n                tr.pitch = interpolate(startPitch, pitch, k);\n            }\n\n            this.animationLoop.set(300); // text fading\n            this._move(zoom !== startZoom, bearing !== startBearing);\n        }, function() {\n            this.zooming = false;\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Flying animation to a specified location/zoom/bearing with automatic curve\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {Number} zoom\n     * @param {Number} bearing\n     * @param {Object} options\n     * @param {Number} [options.speed=1.2] How fast animation occurs\n     * @param {Number} [options.curve=1.42] How much zooming out occurs during animation\n     * @param {Function} options.easing\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    flyTo: function(latlng, zoom, bearing, options) {\n        this.stop();\n\n        options = util.extend({\n            offset: [0, 0],\n            speed: 1.2,\n            curve: 1.42,\n            easing: util.ease\n        }, options);\n\n        latlng = LatLng.convert(latlng);\n\n        var offset = Point.convert(options.offset),\n            tr = this.transform,\n            startZoom = this.getZoom(),\n            startBearing = this.getBearing();\n\n        zoom = zoom === undefined ? startZoom : zoom;\n        bearing = bearing === undefined ? startBearing : this._normalizeBearing(bearing, startBearing);\n\n        var scale = tr.zoomScale(zoom - startZoom),\n            from = tr.point,\n            to = tr.project(latlng).sub(offset.div(scale));\n\n        if (options.animate === false) {\n            return this.setView(latlng, zoom, bearing, this.getPitch());\n        }\n\n        var startWorldSize = tr.worldSize,\n            rho = options.curve,\n            V = options.speed,\n\n            w0 = Math.max(tr.width, tr.height),\n            w1 = w0 / scale,\n            u1 = to.sub(from).mag(),\n            rho2 = rho * rho;\n\n        function r(i) {\n            var b = (w1 * w1 - w0 * w0 + (i ? -1 : 1) * rho2 * rho2 * u1 * u1) / (2 * (i ? w1 : w0) * rho2 * u1);\n            return Math.log(Math.sqrt(b * b + 1) - b);\n        }\n\n        function sinh(n) { return (Math.exp(n) - Math.exp(-n)) / 2; }\n        function cosh(n) { return (Math.exp(n) + Math.exp(-n)) / 2; }\n        function tanh(n) { return sinh(n) / cosh(n); }\n\n        var r0 = r(0),\n            w = function (s) { return (cosh(r0) / cosh(r0 + rho * s)); },\n            u = function (s) { return w0 * ((cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2) / u1; },\n            S = (r(1) - r0) / rho;\n\n        if (Math.abs(u1) < 0.000001) {\n            if (Math.abs(w0 - w1) < 0.000001) return this;\n\n            var k = w1 < w0 ? -1 : 1;\n            S = Math.abs(Math.log(w1 / w0)) / rho;\n\n            u = function() { return 0; };\n            w = function(s) { return Math.exp(k * rho * s); };\n        }\n\n        options.duration = 1000 * S / V;\n\n        this.zooming = true;\n        if (startBearing !== bearing) this.rotating = true;\n\n        this.fire('movestart');\n\n        this._ease(function (k) {\n            var s = k * S,\n                us = u(s);\n\n            tr.zoom = startZoom + tr.scaleZoom(1 / w(s));\n            tr.center = tr.unproject(from.add(to.sub(from).mult(us)), startWorldSize);\n\n            if (bearing !== startBearing) {\n                tr.bearing = interpolate(startBearing, bearing, k);\n            }\n\n            this.animationLoop.set(300); // text fading\n\n            this._move(true, bearing !== startBearing);\n        }, function() {\n            this.zooming = false;\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    // convert bearing so that it's numerically close to the current one so that it interpolates properly\n    _normalizeBearing: function(bearing, currentBearing) {\n        bearing = util.wrap(bearing, -180, 180);\n        var diff = Math.abs(bearing - currentBearing);\n        if (Math.abs(bearing - 360 - currentBearing) < diff) bearing -= 360;\n        if (Math.abs(bearing + 360 - currentBearing) < diff) bearing += 360;\n        return bearing;\n    },\n\n    _updateEasing: function(duration, zoom, bezier) {\n        var easing;\n\n        if (this.ease) {\n            var ease = this.ease,\n                t = (Date.now() - ease.start) / ease.duration,\n                speed = ease.easing(t + 0.01) - ease.easing(t),\n\n                // Quick hack to make new bezier that is continuous with last\n                x = 0.27 / Math.sqrt(speed * speed + 0.0001) * 0.01,\n                y = Math.sqrt(0.27 * 0.27 - x * x);\n\n            easing = util.bezier(x, y, 0.25, 1);\n        } else {\n            easing = bezier ? util.bezier.apply(util, bezier) : util.ease;\n        }\n\n        // store information on current easing\n        this.ease = {\n            start: (new Date()).getTime(),\n            to: Math.pow(2, zoom),\n            duration: duration,\n            easing: easing\n        };\n\n        return easing;\n    }\n}","path":"js/ui/easings.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/easings.js#L59-L62"},"params":[{"title":"param","description":"[x, y]","type":{"type":"NameExpression","name":"Array"},"name":"offset"},{"title":"param","description":null,"type":null,"name":"animOptions"}],"returns":[{"title":"returns","description":null,"type":{"type":"NameExpression","name":"this"}}],"name":"panBy","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","panBy"]},{"description":"Is this map fully loaded? If the style isn't loaded\nor it has a change to the sources or style that isn't\npropagated to its style, return false.","tags":[{"title":"returns","description":"whether the map is loaded","type":{"type":"NameExpression","name":"boolean"}},{"title":"name","name":"loaded"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":653,"column":4},"end":{"line":659,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L653-L659"},"returns":[{"title":"returns","description":"whether the map is loaded","type":{"type":"NameExpression","name":"boolean"}}],"name":"loaded","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","loaded"]},{"description":"Call when a (re-)render of the map is required, e.g. when the\nuser panned or zoomed,f or new data is available.","tags":[{"title":"returns","description":"this","type":{"type":"NameExpression","name":"Map"}},{"title":"name","name":"render"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":683,"column":4},"end":{"line":722,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L683-L722"},"returns":[{"title":"returns","description":"this","type":{"type":"NameExpression","name":"Map"}}],"name":"render","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","render"]},{"description":"Destroys the map's underlying resources, including web workers.","tags":[{"title":"returns","description":"this","type":{"type":"NameExpression","name":"Map"}},{"title":"name","name":"remove"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":728,"column":4},"end":{"line":734,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L728-L734"},"returns":[{"title":"returns","description":"this","type":{"type":"NameExpression","name":"Map"}}],"name":"remove","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","remove"]},{"description":"Pan to a certain location with easing","tags":[{"title":"param","description":"a `LatLng` object","type":{"type":"NameExpression","name":"Object"},"name":"latlng"},{"title":"param","description":null,"type":null,"name":"animOptions"},{"title":"fires","description":"movestart"},{"title":"fires","description":"moveend"},{"title":"returns","description":null,"type":{"type":"NameExpression","name":"this"}},{"title":"name","name":"panTo"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":73,"column":4},"end":{"line":101,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/easings.js","code":"{\n    isEasing: function() {\n        return !!this._abortFn;\n    },\n\n    /**\n     * Stop current animation\n     *\n     * @returns {this}\n     */\n    stop: function() {\n        if (this._abortFn) {\n            this._abortFn.call(this);\n            delete this._abortFn;\n\n            this._finishFn.call(this);\n            delete this._finishFn;\n        }\n        return this;\n    },\n\n    _ease: function(frame, finish, options) {\n        this._finishFn = finish;\n        this._abortFn = browser.timed(function (t) {\n            frame.call(this, options.easing(t));\n            if (t === 1) {\n                delete this._abortFn;\n                this._finishFn.call(this);\n                delete this._finishFn;\n            }\n        }, options.animate === false ? 0 : options.duration, this);\n    },\n\n    /**\n     * Pan by a certain number of pixels\n     *\n     * @param {Array} offset [x, y]\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    panBy: function(offset, options) {\n        this.panTo(this.transform.center, util.extend({offset: Point.convert(offset).mult(-1)}, options));\n        return this;\n    },\n\n    /**\n     * Pan to a certain location with easing\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    panTo: function(latlng, options) {\n        this.stop();\n\n        latlng = LatLng.convert(latlng);\n\n        options = util.extend({\n            duration: 500,\n            easing: util.ease,\n            offset: [0, 0]\n        }, options);\n\n        var tr = this.transform,\n            offset = Point.convert(options.offset).rotate(-tr.angle),\n            from = tr.point,\n            to = tr.project(latlng).sub(offset);\n\n        if (!options.noMoveStart) {\n            this.fire('movestart');\n        }\n\n        this._ease(function(k) {\n            tr.center = tr.unproject(from.add(to.sub(from).mult(k)));\n            this._move();\n        }, function() {\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Zooms to a certain zoom level with easing.\n     *\n     * @param {Number} zoom\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomTo: function(zoom, options) {\n        this.stop();\n\n        options = util.extend({\n            duration: 500\n        }, options);\n\n        options.easing = this._updateEasing(options.duration, zoom, options.easing);\n\n        var tr = this.transform,\n            around = tr.center,\n            startZoom = tr.zoom;\n\n        if (options.around) {\n            around = LatLng.convert(options.around);\n        } else if (options.offset) {\n            around = tr.pointLocation(tr.centerPoint.add(Point.convert(options.offset)));\n        }\n\n        if (options.animate === false) options.duration = 0;\n\n        if (!this.zooming) {\n            this.zooming = true;\n            this.fire('movestart');\n        }\n\n        this._ease(function(k) {\n            tr.setZoomAround(interpolate(startZoom, zoom, k), around);\n            this.animationLoop.set(300); // text fading\n            this._move(true);\n        }, function() {\n            this.ease = null;\n            if (options.duration >= 200) {\n                this.zooming = false;\n                this.fire('moveend');\n            }\n        }, options);\n\n        if (options.duration < 200) {\n            clearTimeout(this._onZoomEnd);\n            this._onZoomEnd = setTimeout(function() {\n                this.zooming = false;\n                this._rerender();\n                this.fire('moveend');\n            }.bind(this), 200);\n        }\n\n        return this;\n    },\n\n    /**\n     * Zoom in by 1 level\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomIn: function(options) {\n        this.zoomTo(this.getZoom() + 1, options);\n    },\n\n    /**\n     * Zoom out by 1 level\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomOut: function(options) {\n        this.zoomTo(this.getZoom() - 1, options);\n    },\n\n    /**\n     * Rotate bearing by a certain number of degrees with easing\n     *\n     * @param {Number} bearing\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    rotateTo: function(bearing, options) {\n        this.stop();\n\n        options = util.extend({\n            duration: 500,\n            easing: util.ease\n        }, options);\n\n        var tr = this.transform,\n            start = this.getBearing(),\n            around = tr.center;\n\n        if (options.around) {\n            around = LatLng.convert(options.around);\n        } else if (options.offset) {\n            around = tr.pointLocation(tr.centerPoint.add(Point.convert(options.offset)));\n        }\n\n        bearing = this._normalizeBearing(bearing, start);\n\n        this.rotating = true;\n        this.fire('movestart');\n\n        this._ease(function(k) {\n            tr.setBearingAround(interpolate(start, bearing, k), around);\n            this._move(false, true);\n        }, function() {\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Sets map bearing to 0 (north) with easing\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    resetNorth: function(options) {\n        return this.rotateTo(0, util.extend({duration: 1000}, options));\n    },\n\n    /**\n     * Zoom to contain certain geographical bounds\n     *\n     * @param {Array} bounds [[minLat, minLng], [maxLat, maxLng]]\n     * @param {Object} options\n     * @param {Number} [options.speed=1.2] How fast animation occurs\n     * @param {Number} [options.curve=1.42] How much zooming out occurs during animation\n     * @param {Function} options.easing\n     * @param {Number} options.padding how much padding there is around the given bounds on each side in pixels\n     * @param {Number} options.maxZoom\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    fitBounds: function(bounds, options) {\n\n        options = util.extend({\n            padding: 0,\n            offset: [0, 0],\n            maxZoom: Infinity\n        }, options);\n\n        bounds = LatLngBounds.convert(bounds);\n\n        var offset = Point.convert(options.offset),\n            tr = this.transform,\n            nw = tr.project(bounds.getNorthWest()),\n            se = tr.project(bounds.getSouthEast()),\n            size = se.sub(nw),\n            center = tr.unproject(nw.add(se).div(2)),\n\n            scaleX = (tr.width - options.padding * 2 - Math.abs(offset.x) * 2) / size.x,\n            scaleY = (tr.height - options.padding * 2 - Math.abs(offset.y) * 2) / size.y,\n\n            zoom = Math.min(tr.scaleZoom(tr.scale * Math.min(scaleX, scaleY)), options.maxZoom);\n\n        return options.linear ?\n            this.easeTo(center, zoom, 0, options) :\n            this.flyTo(center, zoom, 0, options);\n    },\n\n    /**\n     * Easing animation to a specified location/zoom/bearing\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {Number} zoom\n     * @param {Number} bearing\n     * @param {Number} pitch\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    easeTo: function(latlng, zoom, bearing, pitch, options) {\n        this.stop();\n\n        options = util.extend({\n            offset: [0, 0],\n            duration: 500,\n            easing: util.ease\n        }, options);\n\n        var tr = this.transform,\n            offset = Point.convert(options.offset).rotate(-tr.angle),\n            startZoom = this.getZoom(),\n            startBearing = this.getBearing(),\n            startPitch = this.getPitch();\n\n        latlng = LatLng.convert(latlng);\n        zoom = zoom === undefined ? startZoom : zoom;\n        bearing = bearing === undefined ? startBearing : this._normalizeBearing(bearing, startBearing);\n        pitch = pitch === undefined ? startPitch : pitch;\n\n        var scale = tr.zoomScale(zoom - startZoom),\n            from = tr.point,\n            to = latlng ? tr.project(latlng).sub(offset.div(scale)) : tr.point,\n            around;\n\n        if (zoom !== startZoom) {\n            around = tr.pointLocation(tr.centerPoint.add(to.sub(from).div(1 - 1 / scale)));\n            this.zooming = true;\n        }\n        if (startBearing !== bearing) this.rotating = true;\n\n        this.fire('movestart');\n\n        this._ease(function (k) {\n            if (zoom !== startZoom) {\n                tr.setZoomAround(interpolate(startZoom, zoom, k), around);\n            } else {\n                tr.center = tr.unproject(from.add(to.sub(from).mult(k)));\n            }\n\n            if (bearing !== startBearing) {\n                tr.bearing = interpolate(startBearing, bearing, k);\n            }\n\n            if (pitch !== startPitch) {\n                tr.pitch = interpolate(startPitch, pitch, k);\n            }\n\n            this.animationLoop.set(300); // text fading\n            this._move(zoom !== startZoom, bearing !== startBearing);\n        }, function() {\n            this.zooming = false;\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Flying animation to a specified location/zoom/bearing with automatic curve\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {Number} zoom\n     * @param {Number} bearing\n     * @param {Object} options\n     * @param {Number} [options.speed=1.2] How fast animation occurs\n     * @param {Number} [options.curve=1.42] How much zooming out occurs during animation\n     * @param {Function} options.easing\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    flyTo: function(latlng, zoom, bearing, options) {\n        this.stop();\n\n        options = util.extend({\n            offset: [0, 0],\n            speed: 1.2,\n            curve: 1.42,\n            easing: util.ease\n        }, options);\n\n        latlng = LatLng.convert(latlng);\n\n        var offset = Point.convert(options.offset),\n            tr = this.transform,\n            startZoom = this.getZoom(),\n            startBearing = this.getBearing();\n\n        zoom = zoom === undefined ? startZoom : zoom;\n        bearing = bearing === undefined ? startBearing : this._normalizeBearing(bearing, startBearing);\n\n        var scale = tr.zoomScale(zoom - startZoom),\n            from = tr.point,\n            to = tr.project(latlng).sub(offset.div(scale));\n\n        if (options.animate === false) {\n            return this.setView(latlng, zoom, bearing, this.getPitch());\n        }\n\n        var startWorldSize = tr.worldSize,\n            rho = options.curve,\n            V = options.speed,\n\n            w0 = Math.max(tr.width, tr.height),\n            w1 = w0 / scale,\n            u1 = to.sub(from).mag(),\n            rho2 = rho * rho;\n\n        function r(i) {\n            var b = (w1 * w1 - w0 * w0 + (i ? -1 : 1) * rho2 * rho2 * u1 * u1) / (2 * (i ? w1 : w0) * rho2 * u1);\n            return Math.log(Math.sqrt(b * b + 1) - b);\n        }\n\n        function sinh(n) { return (Math.exp(n) - Math.exp(-n)) / 2; }\n        function cosh(n) { return (Math.exp(n) + Math.exp(-n)) / 2; }\n        function tanh(n) { return sinh(n) / cosh(n); }\n\n        var r0 = r(0),\n            w = function (s) { return (cosh(r0) / cosh(r0 + rho * s)); },\n            u = function (s) { return w0 * ((cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2) / u1; },\n            S = (r(1) - r0) / rho;\n\n        if (Math.abs(u1) < 0.000001) {\n            if (Math.abs(w0 - w1) < 0.000001) return this;\n\n            var k = w1 < w0 ? -1 : 1;\n            S = Math.abs(Math.log(w1 / w0)) / rho;\n\n            u = function() { return 0; };\n            w = function(s) { return Math.exp(k * rho * s); };\n        }\n\n        options.duration = 1000 * S / V;\n\n        this.zooming = true;\n        if (startBearing !== bearing) this.rotating = true;\n\n        this.fire('movestart');\n\n        this._ease(function (k) {\n            var s = k * S,\n                us = u(s);\n\n            tr.zoom = startZoom + tr.scaleZoom(1 / w(s));\n            tr.center = tr.unproject(from.add(to.sub(from).mult(us)), startWorldSize);\n\n            if (bearing !== startBearing) {\n                tr.bearing = interpolate(startBearing, bearing, k);\n            }\n\n            this.animationLoop.set(300); // text fading\n\n            this._move(true, bearing !== startBearing);\n        }, function() {\n            this.zooming = false;\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    // convert bearing so that it's numerically close to the current one so that it interpolates properly\n    _normalizeBearing: function(bearing, currentBearing) {\n        bearing = util.wrap(bearing, -180, 180);\n        var diff = Math.abs(bearing - currentBearing);\n        if (Math.abs(bearing - 360 - currentBearing) < diff) bearing -= 360;\n        if (Math.abs(bearing + 360 - currentBearing) < diff) bearing += 360;\n        return bearing;\n    },\n\n    _updateEasing: function(duration, zoom, bezier) {\n        var easing;\n\n        if (this.ease) {\n            var ease = this.ease,\n                t = (Date.now() - ease.start) / ease.duration,\n                speed = ease.easing(t + 0.01) - ease.easing(t),\n\n                // Quick hack to make new bezier that is continuous with last\n                x = 0.27 / Math.sqrt(speed * speed + 0.0001) * 0.01,\n                y = Math.sqrt(0.27 * 0.27 - x * x);\n\n            easing = util.bezier(x, y, 0.25, 1);\n        } else {\n            easing = bezier ? util.bezier.apply(util, bezier) : util.ease;\n        }\n\n        // store information on current easing\n        this.ease = {\n            start: (new Date()).getTime(),\n            to: Math.pow(2, zoom),\n            duration: duration,\n            easing: easing\n        };\n\n        return easing;\n    }\n}","path":"js/ui/easings.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/easings.js#L73-L101"},"params":[{"title":"param","description":"a `LatLng` object","type":{"type":"NameExpression","name":"Object"},"name":"latlng"},{"title":"param","description":null,"type":null,"name":"animOptions"}],"returns":[{"title":"returns","description":null,"type":{"type":"NameExpression","name":"this"}}],"name":"panTo","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","panTo"]},{"description":"Sets map bearing to 0 (north) with easing","tags":[{"title":"param","description":null,"type":null,"name":"animOptions"},{"title":"fires","description":"movestart"},{"title":"fires","description":"moveend"},{"title":"returns","description":null,"type":{"type":"NameExpression","name":"this"}},{"title":"name","name":"resetNorth"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":237,"column":4},"end":{"line":239,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/easings.js","code":"{\n    isEasing: function() {\n        return !!this._abortFn;\n    },\n\n    /**\n     * Stop current animation\n     *\n     * @returns {this}\n     */\n    stop: function() {\n        if (this._abortFn) {\n            this._abortFn.call(this);\n            delete this._abortFn;\n\n            this._finishFn.call(this);\n            delete this._finishFn;\n        }\n        return this;\n    },\n\n    _ease: function(frame, finish, options) {\n        this._finishFn = finish;\n        this._abortFn = browser.timed(function (t) {\n            frame.call(this, options.easing(t));\n            if (t === 1) {\n                delete this._abortFn;\n                this._finishFn.call(this);\n                delete this._finishFn;\n            }\n        }, options.animate === false ? 0 : options.duration, this);\n    },\n\n    /**\n     * Pan by a certain number of pixels\n     *\n     * @param {Array} offset [x, y]\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    panBy: function(offset, options) {\n        this.panTo(this.transform.center, util.extend({offset: Point.convert(offset).mult(-1)}, options));\n        return this;\n    },\n\n    /**\n     * Pan to a certain location with easing\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    panTo: function(latlng, options) {\n        this.stop();\n\n        latlng = LatLng.convert(latlng);\n\n        options = util.extend({\n            duration: 500,\n            easing: util.ease,\n            offset: [0, 0]\n        }, options);\n\n        var tr = this.transform,\n            offset = Point.convert(options.offset).rotate(-tr.angle),\n            from = tr.point,\n            to = tr.project(latlng).sub(offset);\n\n        if (!options.noMoveStart) {\n            this.fire('movestart');\n        }\n\n        this._ease(function(k) {\n            tr.center = tr.unproject(from.add(to.sub(from).mult(k)));\n            this._move();\n        }, function() {\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Zooms to a certain zoom level with easing.\n     *\n     * @param {Number} zoom\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomTo: function(zoom, options) {\n        this.stop();\n\n        options = util.extend({\n            duration: 500\n        }, options);\n\n        options.easing = this._updateEasing(options.duration, zoom, options.easing);\n\n        var tr = this.transform,\n            around = tr.center,\n            startZoom = tr.zoom;\n\n        if (options.around) {\n            around = LatLng.convert(options.around);\n        } else if (options.offset) {\n            around = tr.pointLocation(tr.centerPoint.add(Point.convert(options.offset)));\n        }\n\n        if (options.animate === false) options.duration = 0;\n\n        if (!this.zooming) {\n            this.zooming = true;\n            this.fire('movestart');\n        }\n\n        this._ease(function(k) {\n            tr.setZoomAround(interpolate(startZoom, zoom, k), around);\n            this.animationLoop.set(300); // text fading\n            this._move(true);\n        }, function() {\n            this.ease = null;\n            if (options.duration >= 200) {\n                this.zooming = false;\n                this.fire('moveend');\n            }\n        }, options);\n\n        if (options.duration < 200) {\n            clearTimeout(this._onZoomEnd);\n            this._onZoomEnd = setTimeout(function() {\n                this.zooming = false;\n                this._rerender();\n                this.fire('moveend');\n            }.bind(this), 200);\n        }\n\n        return this;\n    },\n\n    /**\n     * Zoom in by 1 level\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomIn: function(options) {\n        this.zoomTo(this.getZoom() + 1, options);\n    },\n\n    /**\n     * Zoom out by 1 level\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomOut: function(options) {\n        this.zoomTo(this.getZoom() - 1, options);\n    },\n\n    /**\n     * Rotate bearing by a certain number of degrees with easing\n     *\n     * @param {Number} bearing\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    rotateTo: function(bearing, options) {\n        this.stop();\n\n        options = util.extend({\n            duration: 500,\n            easing: util.ease\n        }, options);\n\n        var tr = this.transform,\n            start = this.getBearing(),\n            around = tr.center;\n\n        if (options.around) {\n            around = LatLng.convert(options.around);\n        } else if (options.offset) {\n            around = tr.pointLocation(tr.centerPoint.add(Point.convert(options.offset)));\n        }\n\n        bearing = this._normalizeBearing(bearing, start);\n\n        this.rotating = true;\n        this.fire('movestart');\n\n        this._ease(function(k) {\n            tr.setBearingAround(interpolate(start, bearing, k), around);\n            this._move(false, true);\n        }, function() {\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Sets map bearing to 0 (north) with easing\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    resetNorth: function(options) {\n        return this.rotateTo(0, util.extend({duration: 1000}, options));\n    },\n\n    /**\n     * Zoom to contain certain geographical bounds\n     *\n     * @param {Array} bounds [[minLat, minLng], [maxLat, maxLng]]\n     * @param {Object} options\n     * @param {Number} [options.speed=1.2] How fast animation occurs\n     * @param {Number} [options.curve=1.42] How much zooming out occurs during animation\n     * @param {Function} options.easing\n     * @param {Number} options.padding how much padding there is around the given bounds on each side in pixels\n     * @param {Number} options.maxZoom\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    fitBounds: function(bounds, options) {\n\n        options = util.extend({\n            padding: 0,\n            offset: [0, 0],\n            maxZoom: Infinity\n        }, options);\n\n        bounds = LatLngBounds.convert(bounds);\n\n        var offset = Point.convert(options.offset),\n            tr = this.transform,\n            nw = tr.project(bounds.getNorthWest()),\n            se = tr.project(bounds.getSouthEast()),\n            size = se.sub(nw),\n            center = tr.unproject(nw.add(se).div(2)),\n\n            scaleX = (tr.width - options.padding * 2 - Math.abs(offset.x) * 2) / size.x,\n            scaleY = (tr.height - options.padding * 2 - Math.abs(offset.y) * 2) / size.y,\n\n            zoom = Math.min(tr.scaleZoom(tr.scale * Math.min(scaleX, scaleY)), options.maxZoom);\n\n        return options.linear ?\n            this.easeTo(center, zoom, 0, options) :\n            this.flyTo(center, zoom, 0, options);\n    },\n\n    /**\n     * Easing animation to a specified location/zoom/bearing\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {Number} zoom\n     * @param {Number} bearing\n     * @param {Number} pitch\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    easeTo: function(latlng, zoom, bearing, pitch, options) {\n        this.stop();\n\n        options = util.extend({\n            offset: [0, 0],\n            duration: 500,\n            easing: util.ease\n        }, options);\n\n        var tr = this.transform,\n            offset = Point.convert(options.offset).rotate(-tr.angle),\n            startZoom = this.getZoom(),\n            startBearing = this.getBearing(),\n            startPitch = this.getPitch();\n\n        latlng = LatLng.convert(latlng);\n        zoom = zoom === undefined ? startZoom : zoom;\n        bearing = bearing === undefined ? startBearing : this._normalizeBearing(bearing, startBearing);\n        pitch = pitch === undefined ? startPitch : pitch;\n\n        var scale = tr.zoomScale(zoom - startZoom),\n            from = tr.point,\n            to = latlng ? tr.project(latlng).sub(offset.div(scale)) : tr.point,\n            around;\n\n        if (zoom !== startZoom) {\n            around = tr.pointLocation(tr.centerPoint.add(to.sub(from).div(1 - 1 / scale)));\n            this.zooming = true;\n        }\n        if (startBearing !== bearing) this.rotating = true;\n\n        this.fire('movestart');\n\n        this._ease(function (k) {\n            if (zoom !== startZoom) {\n                tr.setZoomAround(interpolate(startZoom, zoom, k), around);\n            } else {\n                tr.center = tr.unproject(from.add(to.sub(from).mult(k)));\n            }\n\n            if (bearing !== startBearing) {\n                tr.bearing = interpolate(startBearing, bearing, k);\n            }\n\n            if (pitch !== startPitch) {\n                tr.pitch = interpolate(startPitch, pitch, k);\n            }\n\n            this.animationLoop.set(300); // text fading\n            this._move(zoom !== startZoom, bearing !== startBearing);\n        }, function() {\n            this.zooming = false;\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Flying animation to a specified location/zoom/bearing with automatic curve\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {Number} zoom\n     * @param {Number} bearing\n     * @param {Object} options\n     * @param {Number} [options.speed=1.2] How fast animation occurs\n     * @param {Number} [options.curve=1.42] How much zooming out occurs during animation\n     * @param {Function} options.easing\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    flyTo: function(latlng, zoom, bearing, options) {\n        this.stop();\n\n        options = util.extend({\n            offset: [0, 0],\n            speed: 1.2,\n            curve: 1.42,\n            easing: util.ease\n        }, options);\n\n        latlng = LatLng.convert(latlng);\n\n        var offset = Point.convert(options.offset),\n            tr = this.transform,\n            startZoom = this.getZoom(),\n            startBearing = this.getBearing();\n\n        zoom = zoom === undefined ? startZoom : zoom;\n        bearing = bearing === undefined ? startBearing : this._normalizeBearing(bearing, startBearing);\n\n        var scale = tr.zoomScale(zoom - startZoom),\n            from = tr.point,\n            to = tr.project(latlng).sub(offset.div(scale));\n\n        if (options.animate === false) {\n            return this.setView(latlng, zoom, bearing, this.getPitch());\n        }\n\n        var startWorldSize = tr.worldSize,\n            rho = options.curve,\n            V = options.speed,\n\n            w0 = Math.max(tr.width, tr.height),\n            w1 = w0 / scale,\n            u1 = to.sub(from).mag(),\n            rho2 = rho * rho;\n\n        function r(i) {\n            var b = (w1 * w1 - w0 * w0 + (i ? -1 : 1) * rho2 * rho2 * u1 * u1) / (2 * (i ? w1 : w0) * rho2 * u1);\n            return Math.log(Math.sqrt(b * b + 1) - b);\n        }\n\n        function sinh(n) { return (Math.exp(n) - Math.exp(-n)) / 2; }\n        function cosh(n) { return (Math.exp(n) + Math.exp(-n)) / 2; }\n        function tanh(n) { return sinh(n) / cosh(n); }\n\n        var r0 = r(0),\n            w = function (s) { return (cosh(r0) / cosh(r0 + rho * s)); },\n            u = function (s) { return w0 * ((cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2) / u1; },\n            S = (r(1) - r0) / rho;\n\n        if (Math.abs(u1) < 0.000001) {\n            if (Math.abs(w0 - w1) < 0.000001) return this;\n\n            var k = w1 < w0 ? -1 : 1;\n            S = Math.abs(Math.log(w1 / w0)) / rho;\n\n            u = function() { return 0; };\n            w = function(s) { return Math.exp(k * rho * s); };\n        }\n\n        options.duration = 1000 * S / V;\n\n        this.zooming = true;\n        if (startBearing !== bearing) this.rotating = true;\n\n        this.fire('movestart');\n\n        this._ease(function (k) {\n            var s = k * S,\n                us = u(s);\n\n            tr.zoom = startZoom + tr.scaleZoom(1 / w(s));\n            tr.center = tr.unproject(from.add(to.sub(from).mult(us)), startWorldSize);\n\n            if (bearing !== startBearing) {\n                tr.bearing = interpolate(startBearing, bearing, k);\n            }\n\n            this.animationLoop.set(300); // text fading\n\n            this._move(true, bearing !== startBearing);\n        }, function() {\n            this.zooming = false;\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    // convert bearing so that it's numerically close to the current one so that it interpolates properly\n    _normalizeBearing: function(bearing, currentBearing) {\n        bearing = util.wrap(bearing, -180, 180);\n        var diff = Math.abs(bearing - currentBearing);\n        if (Math.abs(bearing - 360 - currentBearing) < diff) bearing -= 360;\n        if (Math.abs(bearing + 360 - currentBearing) < diff) bearing += 360;\n        return bearing;\n    },\n\n    _updateEasing: function(duration, zoom, bezier) {\n        var easing;\n\n        if (this.ease) {\n            var ease = this.ease,\n                t = (Date.now() - ease.start) / ease.duration,\n                speed = ease.easing(t + 0.01) - ease.easing(t),\n\n                // Quick hack to make new bezier that is continuous with last\n                x = 0.27 / Math.sqrt(speed * speed + 0.0001) * 0.01,\n                y = Math.sqrt(0.27 * 0.27 - x * x);\n\n            easing = util.bezier(x, y, 0.25, 1);\n        } else {\n            easing = bezier ? util.bezier.apply(util, bezier) : util.ease;\n        }\n\n        // store information on current easing\n        this.ease = {\n            start: (new Date()).getTime(),\n            to: Math.pow(2, zoom),\n            duration: duration,\n            easing: easing\n        };\n\n        return easing;\n    }\n}","path":"js/ui/easings.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/easings.js#L237-L239"},"params":[{"title":"param","description":null,"type":null,"name":"animOptions"}],"returns":[{"title":"returns","description":null,"type":{"type":"NameExpression","name":"this"}}],"name":"resetNorth","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","resetNorth"]},{"description":"Detect the map's new width and height and resize it.","tags":[{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}},{"title":"name","name":"resize"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":294,"column":4},"end":{"line":315,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L294-L315"},"returns":[{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}}],"name":"resize","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","resize"]},{"description":"Zoom to contain certain geographical bounds","tags":[{"title":"param","description":"[[minLat, minLng], [maxLat, maxLng]]","type":{"type":"NameExpression","name":"Array"},"name":"bounds"},{"title":"param","description":null,"type":{"type":"NameExpression","name":"Object"},"name":"options"},{"title":"name","name":"fitBounds"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":255,"column":4},"end":{"line":280,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/easings.js","code":"{\n    isEasing: function() {\n        return !!this._abortFn;\n    },\n\n    /**\n     * Stop current animation\n     *\n     * @returns {this}\n     */\n    stop: function() {\n        if (this._abortFn) {\n            this._abortFn.call(this);\n            delete this._abortFn;\n\n            this._finishFn.call(this);\n            delete this._finishFn;\n        }\n        return this;\n    },\n\n    _ease: function(frame, finish, options) {\n        this._finishFn = finish;\n        this._abortFn = browser.timed(function (t) {\n            frame.call(this, options.easing(t));\n            if (t === 1) {\n                delete this._abortFn;\n                this._finishFn.call(this);\n                delete this._finishFn;\n            }\n        }, options.animate === false ? 0 : options.duration, this);\n    },\n\n    /**\n     * Pan by a certain number of pixels\n     *\n     * @param {Array} offset [x, y]\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    panBy: function(offset, options) {\n        this.panTo(this.transform.center, util.extend({offset: Point.convert(offset).mult(-1)}, options));\n        return this;\n    },\n\n    /**\n     * Pan to a certain location with easing\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    panTo: function(latlng, options) {\n        this.stop();\n\n        latlng = LatLng.convert(latlng);\n\n        options = util.extend({\n            duration: 500,\n            easing: util.ease,\n            offset: [0, 0]\n        }, options);\n\n        var tr = this.transform,\n            offset = Point.convert(options.offset).rotate(-tr.angle),\n            from = tr.point,\n            to = tr.project(latlng).sub(offset);\n\n        if (!options.noMoveStart) {\n            this.fire('movestart');\n        }\n\n        this._ease(function(k) {\n            tr.center = tr.unproject(from.add(to.sub(from).mult(k)));\n            this._move();\n        }, function() {\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Zooms to a certain zoom level with easing.\n     *\n     * @param {Number} zoom\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomTo: function(zoom, options) {\n        this.stop();\n\n        options = util.extend({\n            duration: 500\n        }, options);\n\n        options.easing = this._updateEasing(options.duration, zoom, options.easing);\n\n        var tr = this.transform,\n            around = tr.center,\n            startZoom = tr.zoom;\n\n        if (options.around) {\n            around = LatLng.convert(options.around);\n        } else if (options.offset) {\n            around = tr.pointLocation(tr.centerPoint.add(Point.convert(options.offset)));\n        }\n\n        if (options.animate === false) options.duration = 0;\n\n        if (!this.zooming) {\n            this.zooming = true;\n            this.fire('movestart');\n        }\n\n        this._ease(function(k) {\n            tr.setZoomAround(interpolate(startZoom, zoom, k), around);\n            this.animationLoop.set(300); // text fading\n            this._move(true);\n        }, function() {\n            this.ease = null;\n            if (options.duration >= 200) {\n                this.zooming = false;\n                this.fire('moveend');\n            }\n        }, options);\n\n        if (options.duration < 200) {\n            clearTimeout(this._onZoomEnd);\n            this._onZoomEnd = setTimeout(function() {\n                this.zooming = false;\n                this._rerender();\n                this.fire('moveend');\n            }.bind(this), 200);\n        }\n\n        return this;\n    },\n\n    /**\n     * Zoom in by 1 level\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomIn: function(options) {\n        this.zoomTo(this.getZoom() + 1, options);\n    },\n\n    /**\n     * Zoom out by 1 level\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomOut: function(options) {\n        this.zoomTo(this.getZoom() - 1, options);\n    },\n\n    /**\n     * Rotate bearing by a certain number of degrees with easing\n     *\n     * @param {Number} bearing\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    rotateTo: function(bearing, options) {\n        this.stop();\n\n        options = util.extend({\n            duration: 500,\n            easing: util.ease\n        }, options);\n\n        var tr = this.transform,\n            start = this.getBearing(),\n            around = tr.center;\n\n        if (options.around) {\n            around = LatLng.convert(options.around);\n        } else if (options.offset) {\n            around = tr.pointLocation(tr.centerPoint.add(Point.convert(options.offset)));\n        }\n\n        bearing = this._normalizeBearing(bearing, start);\n\n        this.rotating = true;\n        this.fire('movestart');\n\n        this._ease(function(k) {\n            tr.setBearingAround(interpolate(start, bearing, k), around);\n            this._move(false, true);\n        }, function() {\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Sets map bearing to 0 (north) with easing\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    resetNorth: function(options) {\n        return this.rotateTo(0, util.extend({duration: 1000}, options));\n    },\n\n    /**\n     * Zoom to contain certain geographical bounds\n     *\n     * @param {Array} bounds [[minLat, minLng], [maxLat, maxLng]]\n     * @param {Object} options\n     * @param {Number} [options.speed=1.2] How fast animation occurs\n     * @param {Number} [options.curve=1.42] How much zooming out occurs during animation\n     * @param {Function} options.easing\n     * @param {Number} options.padding how much padding there is around the given bounds on each side in pixels\n     * @param {Number} options.maxZoom\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    fitBounds: function(bounds, options) {\n\n        options = util.extend({\n            padding: 0,\n            offset: [0, 0],\n            maxZoom: Infinity\n        }, options);\n\n        bounds = LatLngBounds.convert(bounds);\n\n        var offset = Point.convert(options.offset),\n            tr = this.transform,\n            nw = tr.project(bounds.getNorthWest()),\n            se = tr.project(bounds.getSouthEast()),\n            size = se.sub(nw),\n            center = tr.unproject(nw.add(se).div(2)),\n\n            scaleX = (tr.width - options.padding * 2 - Math.abs(offset.x) * 2) / size.x,\n            scaleY = (tr.height - options.padding * 2 - Math.abs(offset.y) * 2) / size.y,\n\n            zoom = Math.min(tr.scaleZoom(tr.scale * Math.min(scaleX, scaleY)), options.maxZoom);\n\n        return options.linear ?\n            this.easeTo(center, zoom, 0, options) :\n            this.flyTo(center, zoom, 0, options);\n    },\n\n    /**\n     * Easing animation to a specified location/zoom/bearing\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {Number} zoom\n     * @param {Number} bearing\n     * @param {Number} pitch\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    easeTo: function(latlng, zoom, bearing, pitch, options) {\n        this.stop();\n\n        options = util.extend({\n            offset: [0, 0],\n            duration: 500,\n            easing: util.ease\n        }, options);\n\n        var tr = this.transform,\n            offset = Point.convert(options.offset).rotate(-tr.angle),\n            startZoom = this.getZoom(),\n            startBearing = this.getBearing(),\n            startPitch = this.getPitch();\n\n        latlng = LatLng.convert(latlng);\n        zoom = zoom === undefined ? startZoom : zoom;\n        bearing = bearing === undefined ? startBearing : this._normalizeBearing(bearing, startBearing);\n        pitch = pitch === undefined ? startPitch : pitch;\n\n        var scale = tr.zoomScale(zoom - startZoom),\n            from = tr.point,\n            to = latlng ? tr.project(latlng).sub(offset.div(scale)) : tr.point,\n            around;\n\n        if (zoom !== startZoom) {\n            around = tr.pointLocation(tr.centerPoint.add(to.sub(from).div(1 - 1 / scale)));\n            this.zooming = true;\n        }\n        if (startBearing !== bearing) this.rotating = true;\n\n        this.fire('movestart');\n\n        this._ease(function (k) {\n            if (zoom !== startZoom) {\n                tr.setZoomAround(interpolate(startZoom, zoom, k), around);\n            } else {\n                tr.center = tr.unproject(from.add(to.sub(from).mult(k)));\n            }\n\n            if (bearing !== startBearing) {\n                tr.bearing = interpolate(startBearing, bearing, k);\n            }\n\n            if (pitch !== startPitch) {\n                tr.pitch = interpolate(startPitch, pitch, k);\n            }\n\n            this.animationLoop.set(300); // text fading\n            this._move(zoom !== startZoom, bearing !== startBearing);\n        }, function() {\n            this.zooming = false;\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Flying animation to a specified location/zoom/bearing with automatic curve\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {Number} zoom\n     * @param {Number} bearing\n     * @param {Object} options\n     * @param {Number} [options.speed=1.2] How fast animation occurs\n     * @param {Number} [options.curve=1.42] How much zooming out occurs during animation\n     * @param {Function} options.easing\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    flyTo: function(latlng, zoom, bearing, options) {\n        this.stop();\n\n        options = util.extend({\n            offset: [0, 0],\n            speed: 1.2,\n            curve: 1.42,\n            easing: util.ease\n        }, options);\n\n        latlng = LatLng.convert(latlng);\n\n        var offset = Point.convert(options.offset),\n            tr = this.transform,\n            startZoom = this.getZoom(),\n            startBearing = this.getBearing();\n\n        zoom = zoom === undefined ? startZoom : zoom;\n        bearing = bearing === undefined ? startBearing : this._normalizeBearing(bearing, startBearing);\n\n        var scale = tr.zoomScale(zoom - startZoom),\n            from = tr.point,\n            to = tr.project(latlng).sub(offset.div(scale));\n\n        if (options.animate === false) {\n            return this.setView(latlng, zoom, bearing, this.getPitch());\n        }\n\n        var startWorldSize = tr.worldSize,\n            rho = options.curve,\n            V = options.speed,\n\n            w0 = Math.max(tr.width, tr.height),\n            w1 = w0 / scale,\n            u1 = to.sub(from).mag(),\n            rho2 = rho * rho;\n\n        function r(i) {\n            var b = (w1 * w1 - w0 * w0 + (i ? -1 : 1) * rho2 * rho2 * u1 * u1) / (2 * (i ? w1 : w0) * rho2 * u1);\n            return Math.log(Math.sqrt(b * b + 1) - b);\n        }\n\n        function sinh(n) { return (Math.exp(n) - Math.exp(-n)) / 2; }\n        function cosh(n) { return (Math.exp(n) + Math.exp(-n)) / 2; }\n        function tanh(n) { return sinh(n) / cosh(n); }\n\n        var r0 = r(0),\n            w = function (s) { return (cosh(r0) / cosh(r0 + rho * s)); },\n            u = function (s) { return w0 * ((cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2) / u1; },\n            S = (r(1) - r0) / rho;\n\n        if (Math.abs(u1) < 0.000001) {\n            if (Math.abs(w0 - w1) < 0.000001) return this;\n\n            var k = w1 < w0 ? -1 : 1;\n            S = Math.abs(Math.log(w1 / w0)) / rho;\n\n            u = function() { return 0; };\n            w = function(s) { return Math.exp(k * rho * s); };\n        }\n\n        options.duration = 1000 * S / V;\n\n        this.zooming = true;\n        if (startBearing !== bearing) this.rotating = true;\n\n        this.fire('movestart');\n\n        this._ease(function (k) {\n            var s = k * S,\n                us = u(s);\n\n            tr.zoom = startZoom + tr.scaleZoom(1 / w(s));\n            tr.center = tr.unproject(from.add(to.sub(from).mult(us)), startWorldSize);\n\n            if (bearing !== startBearing) {\n                tr.bearing = interpolate(startBearing, bearing, k);\n            }\n\n            this.animationLoop.set(300); // text fading\n\n            this._move(true, bearing !== startBearing);\n        }, function() {\n            this.zooming = false;\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    // convert bearing so that it's numerically close to the current one so that it interpolates properly\n    _normalizeBearing: function(bearing, currentBearing) {\n        bearing = util.wrap(bearing, -180, 180);\n        var diff = Math.abs(bearing - currentBearing);\n        if (Math.abs(bearing - 360 - currentBearing) < diff) bearing -= 360;\n        if (Math.abs(bearing + 360 - currentBearing) < diff) bearing += 360;\n        return bearing;\n    },\n\n    _updateEasing: function(duration, zoom, bezier) {\n        var easing;\n\n        if (this.ease) {\n            var ease = this.ease,\n                t = (Date.now() - ease.start) / ease.duration,\n                speed = ease.easing(t + 0.01) - ease.easing(t),\n\n                // Quick hack to make new bezier that is continuous with last\n                x = 0.27 / Math.sqrt(speed * speed + 0.0001) * 0.01,\n                y = Math.sqrt(0.27 * 0.27 - x * x);\n\n            easing = util.bezier(x, y, 0.25, 1);\n        } else {\n            easing = bezier ? util.bezier.apply(util, bezier) : util.ease;\n        }\n\n        // store information on current easing\n        this.ease = {\n            start: (new Date()).getTime(),\n            to: Math.pow(2, zoom),\n            duration: duration,\n            easing: easing\n        };\n\n        return easing;\n    }\n}","path":"js/ui/easings.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/easings.js#L255-L280"},"params":[{"title":"param","description":"[[minLat, minLng], [maxLat, maxLng]]","type":{"type":"NameExpression","name":"Array"},"name":"bounds"},{"title":"param","description":null,"type":{"type":"NameExpression","name":"Object"},"name":"options"}],"name":"fitBounds","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","fitBounds"]},{"description":"Easing animation to a specified location/zoom/bearing","tags":[{"title":"param","description":"a `LatLng` object","type":{"type":"NameExpression","name":"Object"},"name":"latlng"},{"title":"param","description":null,"type":{"type":"NameExpression","name":"Number"},"name":"zoom"},{"title":"param","description":null,"type":{"type":"NameExpression","name":"Number"},"name":"bearing"},{"title":"param","description":null,"type":{"type":"NameExpression","name":"Number"},"name":"pitch"},{"title":"param","description":null,"type":null,"name":"animOptions"},{"title":"fires","description":"movestart"},{"title":"fires","description":"moveend"},{"title":"returns","description":null,"type":{"type":"NameExpression","name":"this"}},{"title":"name","name":"easeTo"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":294,"column":4},"end":{"line":351,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/easings.js","code":"{\n    isEasing: function() {\n        return !!this._abortFn;\n    },\n\n    /**\n     * Stop current animation\n     *\n     * @returns {this}\n     */\n    stop: function() {\n        if (this._abortFn) {\n            this._abortFn.call(this);\n            delete this._abortFn;\n\n            this._finishFn.call(this);\n            delete this._finishFn;\n        }\n        return this;\n    },\n\n    _ease: function(frame, finish, options) {\n        this._finishFn = finish;\n        this._abortFn = browser.timed(function (t) {\n            frame.call(this, options.easing(t));\n            if (t === 1) {\n                delete this._abortFn;\n                this._finishFn.call(this);\n                delete this._finishFn;\n            }\n        }, options.animate === false ? 0 : options.duration, this);\n    },\n\n    /**\n     * Pan by a certain number of pixels\n     *\n     * @param {Array} offset [x, y]\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    panBy: function(offset, options) {\n        this.panTo(this.transform.center, util.extend({offset: Point.convert(offset).mult(-1)}, options));\n        return this;\n    },\n\n    /**\n     * Pan to a certain location with easing\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    panTo: function(latlng, options) {\n        this.stop();\n\n        latlng = LatLng.convert(latlng);\n\n        options = util.extend({\n            duration: 500,\n            easing: util.ease,\n            offset: [0, 0]\n        }, options);\n\n        var tr = this.transform,\n            offset = Point.convert(options.offset).rotate(-tr.angle),\n            from = tr.point,\n            to = tr.project(latlng).sub(offset);\n\n        if (!options.noMoveStart) {\n            this.fire('movestart');\n        }\n\n        this._ease(function(k) {\n            tr.center = tr.unproject(from.add(to.sub(from).mult(k)));\n            this._move();\n        }, function() {\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Zooms to a certain zoom level with easing.\n     *\n     * @param {Number} zoom\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomTo: function(zoom, options) {\n        this.stop();\n\n        options = util.extend({\n            duration: 500\n        }, options);\n\n        options.easing = this._updateEasing(options.duration, zoom, options.easing);\n\n        var tr = this.transform,\n            around = tr.center,\n            startZoom = tr.zoom;\n\n        if (options.around) {\n            around = LatLng.convert(options.around);\n        } else if (options.offset) {\n            around = tr.pointLocation(tr.centerPoint.add(Point.convert(options.offset)));\n        }\n\n        if (options.animate === false) options.duration = 0;\n\n        if (!this.zooming) {\n            this.zooming = true;\n            this.fire('movestart');\n        }\n\n        this._ease(function(k) {\n            tr.setZoomAround(interpolate(startZoom, zoom, k), around);\n            this.animationLoop.set(300); // text fading\n            this._move(true);\n        }, function() {\n            this.ease = null;\n            if (options.duration >= 200) {\n                this.zooming = false;\n                this.fire('moveend');\n            }\n        }, options);\n\n        if (options.duration < 200) {\n            clearTimeout(this._onZoomEnd);\n            this._onZoomEnd = setTimeout(function() {\n                this.zooming = false;\n                this._rerender();\n                this.fire('moveend');\n            }.bind(this), 200);\n        }\n\n        return this;\n    },\n\n    /**\n     * Zoom in by 1 level\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomIn: function(options) {\n        this.zoomTo(this.getZoom() + 1, options);\n    },\n\n    /**\n     * Zoom out by 1 level\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomOut: function(options) {\n        this.zoomTo(this.getZoom() - 1, options);\n    },\n\n    /**\n     * Rotate bearing by a certain number of degrees with easing\n     *\n     * @param {Number} bearing\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    rotateTo: function(bearing, options) {\n        this.stop();\n\n        options = util.extend({\n            duration: 500,\n            easing: util.ease\n        }, options);\n\n        var tr = this.transform,\n            start = this.getBearing(),\n            around = tr.center;\n\n        if (options.around) {\n            around = LatLng.convert(options.around);\n        } else if (options.offset) {\n            around = tr.pointLocation(tr.centerPoint.add(Point.convert(options.offset)));\n        }\n\n        bearing = this._normalizeBearing(bearing, start);\n\n        this.rotating = true;\n        this.fire('movestart');\n\n        this._ease(function(k) {\n            tr.setBearingAround(interpolate(start, bearing, k), around);\n            this._move(false, true);\n        }, function() {\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Sets map bearing to 0 (north) with easing\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    resetNorth: function(options) {\n        return this.rotateTo(0, util.extend({duration: 1000}, options));\n    },\n\n    /**\n     * Zoom to contain certain geographical bounds\n     *\n     * @param {Array} bounds [[minLat, minLng], [maxLat, maxLng]]\n     * @param {Object} options\n     * @param {Number} [options.speed=1.2] How fast animation occurs\n     * @param {Number} [options.curve=1.42] How much zooming out occurs during animation\n     * @param {Function} options.easing\n     * @param {Number} options.padding how much padding there is around the given bounds on each side in pixels\n     * @param {Number} options.maxZoom\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    fitBounds: function(bounds, options) {\n\n        options = util.extend({\n            padding: 0,\n            offset: [0, 0],\n            maxZoom: Infinity\n        }, options);\n\n        bounds = LatLngBounds.convert(bounds);\n\n        var offset = Point.convert(options.offset),\n            tr = this.transform,\n            nw = tr.project(bounds.getNorthWest()),\n            se = tr.project(bounds.getSouthEast()),\n            size = se.sub(nw),\n            center = tr.unproject(nw.add(se).div(2)),\n\n            scaleX = (tr.width - options.padding * 2 - Math.abs(offset.x) * 2) / size.x,\n            scaleY = (tr.height - options.padding * 2 - Math.abs(offset.y) * 2) / size.y,\n\n            zoom = Math.min(tr.scaleZoom(tr.scale * Math.min(scaleX, scaleY)), options.maxZoom);\n\n        return options.linear ?\n            this.easeTo(center, zoom, 0, options) :\n            this.flyTo(center, zoom, 0, options);\n    },\n\n    /**\n     * Easing animation to a specified location/zoom/bearing\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {Number} zoom\n     * @param {Number} bearing\n     * @param {Number} pitch\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    easeTo: function(latlng, zoom, bearing, pitch, options) {\n        this.stop();\n\n        options = util.extend({\n            offset: [0, 0],\n            duration: 500,\n            easing: util.ease\n        }, options);\n\n        var tr = this.transform,\n            offset = Point.convert(options.offset).rotate(-tr.angle),\n            startZoom = this.getZoom(),\n            startBearing = this.getBearing(),\n            startPitch = this.getPitch();\n\n        latlng = LatLng.convert(latlng);\n        zoom = zoom === undefined ? startZoom : zoom;\n        bearing = bearing === undefined ? startBearing : this._normalizeBearing(bearing, startBearing);\n        pitch = pitch === undefined ? startPitch : pitch;\n\n        var scale = tr.zoomScale(zoom - startZoom),\n            from = tr.point,\n            to = latlng ? tr.project(latlng).sub(offset.div(scale)) : tr.point,\n            around;\n\n        if (zoom !== startZoom) {\n            around = tr.pointLocation(tr.centerPoint.add(to.sub(from).div(1 - 1 / scale)));\n            this.zooming = true;\n        }\n        if (startBearing !== bearing) this.rotating = true;\n\n        this.fire('movestart');\n\n        this._ease(function (k) {\n            if (zoom !== startZoom) {\n                tr.setZoomAround(interpolate(startZoom, zoom, k), around);\n            } else {\n                tr.center = tr.unproject(from.add(to.sub(from).mult(k)));\n            }\n\n            if (bearing !== startBearing) {\n                tr.bearing = interpolate(startBearing, bearing, k);\n            }\n\n            if (pitch !== startPitch) {\n                tr.pitch = interpolate(startPitch, pitch, k);\n            }\n\n            this.animationLoop.set(300); // text fading\n            this._move(zoom !== startZoom, bearing !== startBearing);\n        }, function() {\n            this.zooming = false;\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Flying animation to a specified location/zoom/bearing with automatic curve\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {Number} zoom\n     * @param {Number} bearing\n     * @param {Object} options\n     * @param {Number} [options.speed=1.2] How fast animation occurs\n     * @param {Number} [options.curve=1.42] How much zooming out occurs during animation\n     * @param {Function} options.easing\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    flyTo: function(latlng, zoom, bearing, options) {\n        this.stop();\n\n        options = util.extend({\n            offset: [0, 0],\n            speed: 1.2,\n            curve: 1.42,\n            easing: util.ease\n        }, options);\n\n        latlng = LatLng.convert(latlng);\n\n        var offset = Point.convert(options.offset),\n            tr = this.transform,\n            startZoom = this.getZoom(),\n            startBearing = this.getBearing();\n\n        zoom = zoom === undefined ? startZoom : zoom;\n        bearing = bearing === undefined ? startBearing : this._normalizeBearing(bearing, startBearing);\n\n        var scale = tr.zoomScale(zoom - startZoom),\n            from = tr.point,\n            to = tr.project(latlng).sub(offset.div(scale));\n\n        if (options.animate === false) {\n            return this.setView(latlng, zoom, bearing, this.getPitch());\n        }\n\n        var startWorldSize = tr.worldSize,\n            rho = options.curve,\n            V = options.speed,\n\n            w0 = Math.max(tr.width, tr.height),\n            w1 = w0 / scale,\n            u1 = to.sub(from).mag(),\n            rho2 = rho * rho;\n\n        function r(i) {\n            var b = (w1 * w1 - w0 * w0 + (i ? -1 : 1) * rho2 * rho2 * u1 * u1) / (2 * (i ? w1 : w0) * rho2 * u1);\n            return Math.log(Math.sqrt(b * b + 1) - b);\n        }\n\n        function sinh(n) { return (Math.exp(n) - Math.exp(-n)) / 2; }\n        function cosh(n) { return (Math.exp(n) + Math.exp(-n)) / 2; }\n        function tanh(n) { return sinh(n) / cosh(n); }\n\n        var r0 = r(0),\n            w = function (s) { return (cosh(r0) / cosh(r0 + rho * s)); },\n            u = function (s) { return w0 * ((cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2) / u1; },\n            S = (r(1) - r0) / rho;\n\n        if (Math.abs(u1) < 0.000001) {\n            if (Math.abs(w0 - w1) < 0.000001) return this;\n\n            var k = w1 < w0 ? -1 : 1;\n            S = Math.abs(Math.log(w1 / w0)) / rho;\n\n            u = function() { return 0; };\n            w = function(s) { return Math.exp(k * rho * s); };\n        }\n\n        options.duration = 1000 * S / V;\n\n        this.zooming = true;\n        if (startBearing !== bearing) this.rotating = true;\n\n        this.fire('movestart');\n\n        this._ease(function (k) {\n            var s = k * S,\n                us = u(s);\n\n            tr.zoom = startZoom + tr.scaleZoom(1 / w(s));\n            tr.center = tr.unproject(from.add(to.sub(from).mult(us)), startWorldSize);\n\n            if (bearing !== startBearing) {\n                tr.bearing = interpolate(startBearing, bearing, k);\n            }\n\n            this.animationLoop.set(300); // text fading\n\n            this._move(true, bearing !== startBearing);\n        }, function() {\n            this.zooming = false;\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    // convert bearing so that it's numerically close to the current one so that it interpolates properly\n    _normalizeBearing: function(bearing, currentBearing) {\n        bearing = util.wrap(bearing, -180, 180);\n        var diff = Math.abs(bearing - currentBearing);\n        if (Math.abs(bearing - 360 - currentBearing) < diff) bearing -= 360;\n        if (Math.abs(bearing + 360 - currentBearing) < diff) bearing += 360;\n        return bearing;\n    },\n\n    _updateEasing: function(duration, zoom, bezier) {\n        var easing;\n\n        if (this.ease) {\n            var ease = this.ease,\n                t = (Date.now() - ease.start) / ease.duration,\n                speed = ease.easing(t + 0.01) - ease.easing(t),\n\n                // Quick hack to make new bezier that is continuous with last\n                x = 0.27 / Math.sqrt(speed * speed + 0.0001) * 0.01,\n                y = Math.sqrt(0.27 * 0.27 - x * x);\n\n            easing = util.bezier(x, y, 0.25, 1);\n        } else {\n            easing = bezier ? util.bezier.apply(util, bezier) : util.ease;\n        }\n\n        // store information on current easing\n        this.ease = {\n            start: (new Date()).getTime(),\n            to: Math.pow(2, zoom),\n            duration: duration,\n            easing: easing\n        };\n\n        return easing;\n    }\n}","path":"js/ui/easings.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/easings.js#L294-L351"},"params":[{"title":"param","description":"a `LatLng` object","type":{"type":"NameExpression","name":"Object"},"name":"latlng"},{"title":"param","description":null,"type":{"type":"NameExpression","name":"Number"},"name":"zoom"},{"title":"param","description":null,"type":{"type":"NameExpression","name":"Number"},"name":"bearing"},{"title":"param","description":null,"type":{"type":"NameExpression","name":"Number"},"name":"pitch"},{"title":"param","description":null,"type":null,"name":"animOptions"}],"returns":[{"title":"returns","description":null,"type":{"type":"NameExpression","name":"this"}}],"name":"easeTo","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","easeTo"]},{"description":"Flying animation to a specified location/zoom/bearing with automatic curve","tags":[{"title":"param","description":"a `LatLng` object","type":{"type":"NameExpression","name":"Object"},"name":"latlng"},{"title":"param","description":null,"type":{"type":"NameExpression","name":"Number"},"name":"zoom"},{"title":"param","description":null,"type":{"type":"NameExpression","name":"Number"},"name":"bearing"},{"title":"param","description":null,"type":{"type":"NameExpression","name":"Object"},"name":"options"},{"title":"name","name":"flyTo"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":367,"column":4},"end":{"line":456,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/easings.js","code":"{\n    isEasing: function() {\n        return !!this._abortFn;\n    },\n\n    /**\n     * Stop current animation\n     *\n     * @returns {this}\n     */\n    stop: function() {\n        if (this._abortFn) {\n            this._abortFn.call(this);\n            delete this._abortFn;\n\n            this._finishFn.call(this);\n            delete this._finishFn;\n        }\n        return this;\n    },\n\n    _ease: function(frame, finish, options) {\n        this._finishFn = finish;\n        this._abortFn = browser.timed(function (t) {\n            frame.call(this, options.easing(t));\n            if (t === 1) {\n                delete this._abortFn;\n                this._finishFn.call(this);\n                delete this._finishFn;\n            }\n        }, options.animate === false ? 0 : options.duration, this);\n    },\n\n    /**\n     * Pan by a certain number of pixels\n     *\n     * @param {Array} offset [x, y]\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    panBy: function(offset, options) {\n        this.panTo(this.transform.center, util.extend({offset: Point.convert(offset).mult(-1)}, options));\n        return this;\n    },\n\n    /**\n     * Pan to a certain location with easing\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    panTo: function(latlng, options) {\n        this.stop();\n\n        latlng = LatLng.convert(latlng);\n\n        options = util.extend({\n            duration: 500,\n            easing: util.ease,\n            offset: [0, 0]\n        }, options);\n\n        var tr = this.transform,\n            offset = Point.convert(options.offset).rotate(-tr.angle),\n            from = tr.point,\n            to = tr.project(latlng).sub(offset);\n\n        if (!options.noMoveStart) {\n            this.fire('movestart');\n        }\n\n        this._ease(function(k) {\n            tr.center = tr.unproject(from.add(to.sub(from).mult(k)));\n            this._move();\n        }, function() {\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Zooms to a certain zoom level with easing.\n     *\n     * @param {Number} zoom\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomTo: function(zoom, options) {\n        this.stop();\n\n        options = util.extend({\n            duration: 500\n        }, options);\n\n        options.easing = this._updateEasing(options.duration, zoom, options.easing);\n\n        var tr = this.transform,\n            around = tr.center,\n            startZoom = tr.zoom;\n\n        if (options.around) {\n            around = LatLng.convert(options.around);\n        } else if (options.offset) {\n            around = tr.pointLocation(tr.centerPoint.add(Point.convert(options.offset)));\n        }\n\n        if (options.animate === false) options.duration = 0;\n\n        if (!this.zooming) {\n            this.zooming = true;\n            this.fire('movestart');\n        }\n\n        this._ease(function(k) {\n            tr.setZoomAround(interpolate(startZoom, zoom, k), around);\n            this.animationLoop.set(300); // text fading\n            this._move(true);\n        }, function() {\n            this.ease = null;\n            if (options.duration >= 200) {\n                this.zooming = false;\n                this.fire('moveend');\n            }\n        }, options);\n\n        if (options.duration < 200) {\n            clearTimeout(this._onZoomEnd);\n            this._onZoomEnd = setTimeout(function() {\n                this.zooming = false;\n                this._rerender();\n                this.fire('moveend');\n            }.bind(this), 200);\n        }\n\n        return this;\n    },\n\n    /**\n     * Zoom in by 1 level\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomIn: function(options) {\n        this.zoomTo(this.getZoom() + 1, options);\n    },\n\n    /**\n     * Zoom out by 1 level\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomOut: function(options) {\n        this.zoomTo(this.getZoom() - 1, options);\n    },\n\n    /**\n     * Rotate bearing by a certain number of degrees with easing\n     *\n     * @param {Number} bearing\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    rotateTo: function(bearing, options) {\n        this.stop();\n\n        options = util.extend({\n            duration: 500,\n            easing: util.ease\n        }, options);\n\n        var tr = this.transform,\n            start = this.getBearing(),\n            around = tr.center;\n\n        if (options.around) {\n            around = LatLng.convert(options.around);\n        } else if (options.offset) {\n            around = tr.pointLocation(tr.centerPoint.add(Point.convert(options.offset)));\n        }\n\n        bearing = this._normalizeBearing(bearing, start);\n\n        this.rotating = true;\n        this.fire('movestart');\n\n        this._ease(function(k) {\n            tr.setBearingAround(interpolate(start, bearing, k), around);\n            this._move(false, true);\n        }, function() {\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Sets map bearing to 0 (north) with easing\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    resetNorth: function(options) {\n        return this.rotateTo(0, util.extend({duration: 1000}, options));\n    },\n\n    /**\n     * Zoom to contain certain geographical bounds\n     *\n     * @param {Array} bounds [[minLat, minLng], [maxLat, maxLng]]\n     * @param {Object} options\n     * @param {Number} [options.speed=1.2] How fast animation occurs\n     * @param {Number} [options.curve=1.42] How much zooming out occurs during animation\n     * @param {Function} options.easing\n     * @param {Number} options.padding how much padding there is around the given bounds on each side in pixels\n     * @param {Number} options.maxZoom\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    fitBounds: function(bounds, options) {\n\n        options = util.extend({\n            padding: 0,\n            offset: [0, 0],\n            maxZoom: Infinity\n        }, options);\n\n        bounds = LatLngBounds.convert(bounds);\n\n        var offset = Point.convert(options.offset),\n            tr = this.transform,\n            nw = tr.project(bounds.getNorthWest()),\n            se = tr.project(bounds.getSouthEast()),\n            size = se.sub(nw),\n            center = tr.unproject(nw.add(se).div(2)),\n\n            scaleX = (tr.width - options.padding * 2 - Math.abs(offset.x) * 2) / size.x,\n            scaleY = (tr.height - options.padding * 2 - Math.abs(offset.y) * 2) / size.y,\n\n            zoom = Math.min(tr.scaleZoom(tr.scale * Math.min(scaleX, scaleY)), options.maxZoom);\n\n        return options.linear ?\n            this.easeTo(center, zoom, 0, options) :\n            this.flyTo(center, zoom, 0, options);\n    },\n\n    /**\n     * Easing animation to a specified location/zoom/bearing\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {Number} zoom\n     * @param {Number} bearing\n     * @param {Number} pitch\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    easeTo: function(latlng, zoom, bearing, pitch, options) {\n        this.stop();\n\n        options = util.extend({\n            offset: [0, 0],\n            duration: 500,\n            easing: util.ease\n        }, options);\n\n        var tr = this.transform,\n            offset = Point.convert(options.offset).rotate(-tr.angle),\n            startZoom = this.getZoom(),\n            startBearing = this.getBearing(),\n            startPitch = this.getPitch();\n\n        latlng = LatLng.convert(latlng);\n        zoom = zoom === undefined ? startZoom : zoom;\n        bearing = bearing === undefined ? startBearing : this._normalizeBearing(bearing, startBearing);\n        pitch = pitch === undefined ? startPitch : pitch;\n\n        var scale = tr.zoomScale(zoom - startZoom),\n            from = tr.point,\n            to = latlng ? tr.project(latlng).sub(offset.div(scale)) : tr.point,\n            around;\n\n        if (zoom !== startZoom) {\n            around = tr.pointLocation(tr.centerPoint.add(to.sub(from).div(1 - 1 / scale)));\n            this.zooming = true;\n        }\n        if (startBearing !== bearing) this.rotating = true;\n\n        this.fire('movestart');\n\n        this._ease(function (k) {\n            if (zoom !== startZoom) {\n                tr.setZoomAround(interpolate(startZoom, zoom, k), around);\n            } else {\n                tr.center = tr.unproject(from.add(to.sub(from).mult(k)));\n            }\n\n            if (bearing !== startBearing) {\n                tr.bearing = interpolate(startBearing, bearing, k);\n            }\n\n            if (pitch !== startPitch) {\n                tr.pitch = interpolate(startPitch, pitch, k);\n            }\n\n            this.animationLoop.set(300); // text fading\n            this._move(zoom !== startZoom, bearing !== startBearing);\n        }, function() {\n            this.zooming = false;\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Flying animation to a specified location/zoom/bearing with automatic curve\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {Number} zoom\n     * @param {Number} bearing\n     * @param {Object} options\n     * @param {Number} [options.speed=1.2] How fast animation occurs\n     * @param {Number} [options.curve=1.42] How much zooming out occurs during animation\n     * @param {Function} options.easing\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    flyTo: function(latlng, zoom, bearing, options) {\n        this.stop();\n\n        options = util.extend({\n            offset: [0, 0],\n            speed: 1.2,\n            curve: 1.42,\n            easing: util.ease\n        }, options);\n\n        latlng = LatLng.convert(latlng);\n\n        var offset = Point.convert(options.offset),\n            tr = this.transform,\n            startZoom = this.getZoom(),\n            startBearing = this.getBearing();\n\n        zoom = zoom === undefined ? startZoom : zoom;\n        bearing = bearing === undefined ? startBearing : this._normalizeBearing(bearing, startBearing);\n\n        var scale = tr.zoomScale(zoom - startZoom),\n            from = tr.point,\n            to = tr.project(latlng).sub(offset.div(scale));\n\n        if (options.animate === false) {\n            return this.setView(latlng, zoom, bearing, this.getPitch());\n        }\n\n        var startWorldSize = tr.worldSize,\n            rho = options.curve,\n            V = options.speed,\n\n            w0 = Math.max(tr.width, tr.height),\n            w1 = w0 / scale,\n            u1 = to.sub(from).mag(),\n            rho2 = rho * rho;\n\n        function r(i) {\n            var b = (w1 * w1 - w0 * w0 + (i ? -1 : 1) * rho2 * rho2 * u1 * u1) / (2 * (i ? w1 : w0) * rho2 * u1);\n            return Math.log(Math.sqrt(b * b + 1) - b);\n        }\n\n        function sinh(n) { return (Math.exp(n) - Math.exp(-n)) / 2; }\n        function cosh(n) { return (Math.exp(n) + Math.exp(-n)) / 2; }\n        function tanh(n) { return sinh(n) / cosh(n); }\n\n        var r0 = r(0),\n            w = function (s) { return (cosh(r0) / cosh(r0 + rho * s)); },\n            u = function (s) { return w0 * ((cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2) / u1; },\n            S = (r(1) - r0) / rho;\n\n        if (Math.abs(u1) < 0.000001) {\n            if (Math.abs(w0 - w1) < 0.000001) return this;\n\n            var k = w1 < w0 ? -1 : 1;\n            S = Math.abs(Math.log(w1 / w0)) / rho;\n\n            u = function() { return 0; };\n            w = function(s) { return Math.exp(k * rho * s); };\n        }\n\n        options.duration = 1000 * S / V;\n\n        this.zooming = true;\n        if (startBearing !== bearing) this.rotating = true;\n\n        this.fire('movestart');\n\n        this._ease(function (k) {\n            var s = k * S,\n                us = u(s);\n\n            tr.zoom = startZoom + tr.scaleZoom(1 / w(s));\n            tr.center = tr.unproject(from.add(to.sub(from).mult(us)), startWorldSize);\n\n            if (bearing !== startBearing) {\n                tr.bearing = interpolate(startBearing, bearing, k);\n            }\n\n            this.animationLoop.set(300); // text fading\n\n            this._move(true, bearing !== startBearing);\n        }, function() {\n            this.zooming = false;\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    // convert bearing so that it's numerically close to the current one so that it interpolates properly\n    _normalizeBearing: function(bearing, currentBearing) {\n        bearing = util.wrap(bearing, -180, 180);\n        var diff = Math.abs(bearing - currentBearing);\n        if (Math.abs(bearing - 360 - currentBearing) < diff) bearing -= 360;\n        if (Math.abs(bearing + 360 - currentBearing) < diff) bearing += 360;\n        return bearing;\n    },\n\n    _updateEasing: function(duration, zoom, bezier) {\n        var easing;\n\n        if (this.ease) {\n            var ease = this.ease,\n                t = (Date.now() - ease.start) / ease.duration,\n                speed = ease.easing(t + 0.01) - ease.easing(t),\n\n                // Quick hack to make new bezier that is continuous with last\n                x = 0.27 / Math.sqrt(speed * speed + 0.0001) * 0.01,\n                y = Math.sqrt(0.27 * 0.27 - x * x);\n\n            easing = util.bezier(x, y, 0.25, 1);\n        } else {\n            easing = bezier ? util.bezier.apply(util, bezier) : util.ease;\n        }\n\n        // store information on current easing\n        this.ease = {\n            start: (new Date()).getTime(),\n            to: Math.pow(2, zoom),\n            duration: duration,\n            easing: easing\n        };\n\n        return easing;\n    }\n}","path":"js/ui/easings.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/easings.js#L367-L456"},"params":[{"title":"param","description":"a `LatLng` object","type":{"type":"NameExpression","name":"Object"},"name":"latlng"},{"title":"param","description":null,"type":{"type":"NameExpression","name":"Number"},"name":"zoom"},{"title":"param","description":null,"type":{"type":"NameExpression","name":"Number"},"name":"bearing"},{"title":"param","description":null,"type":{"type":"NameExpression","name":"Object"},"name":"options"}],"name":"flyTo","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","flyTo"]},{"description":"Get the current view geographical point","tags":[{"title":"returns","description":null,"type":{"type":"NameExpression","name":"LatLng"}},{"title":"name","name":"getCenter"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":201,"column":4},"end":{"line":201,"column":59}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L201-L201"},"returns":[{"title":"returns","description":null,"type":{"type":"NameExpression","name":"LatLng"}}],"name":"getCenter","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","getCenter"]},{"description":"Get the current bearing in degrees","tags":[{"title":"returns","description":null,"type":{"type":"NameExpression","name":"number"}},{"title":"name","name":"getBearing"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":213,"column":4},"end":{"line":213,"column":61}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L213-L213"},"returns":[{"title":"returns","description":null,"type":{"type":"NameExpression","name":"number"}}],"name":"getBearing","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","getBearing"]},{"description":"Return an array of the current active style classes","tags":[{"title":"returns","description":null,"type":{"type":"NameExpression","name":"boolean"}},{"title":"name","name":"getClasses"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":285,"column":4},"end":{"line":287,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L285-L287"},"returns":[{"title":"returns","description":null,"type":{"type":"NameExpression","name":"boolean"}}],"name":"getClasses","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","getClasses"]},{"description":"Get the map's geographical bounds","tags":[{"title":"returns","description":null,"type":{"type":"NameExpression","name":"LatLngBounds"}},{"title":"name","name":"getBounds"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":322,"column":4},"end":{"line":326,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L322-L326"},"returns":[{"title":"returns","description":null,"type":{"type":"NameExpression","name":"LatLngBounds"}}],"name":"getBounds","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","getBounds"]},{"description":"Get all features at a point ([x, y])","tags":[{"title":"param","description":"[x, y] pixel coordinates","type":{"type":"TypeApplication","expression":{"type":"NameExpression","name":"Array"},"applications":[{"type":"NameExpression","name":"number"}]},"name":"point"},{"title":"param","description":null,"type":{"type":"NameExpression","name":"Object"},"name":"params"},{"title":"name","name":"featuresAt"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":364,"column":4},"end":{"line":368,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L364-L368"},"params":[{"title":"param","description":"[x, y] pixel coordinates","type":{"type":"TypeApplication","expression":{"type":"NameExpression","name":"Array"},"applications":[{"type":"NameExpression","name":"number"}]},"name":"point"},{"title":"param","description":null,"type":{"type":"NameExpression","name":"Object"},"name":"params"}],"name":"featuresAt","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","featuresAt"]},{"description":"Get the filter for a given style layer.","tags":[{"title":"param","description":"ID of a layer","type":{"type":"NameExpression","name":"string"},"name":"layer"},{"title":"returns","description":"filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)","type":{"type":"NameExpression","name":"Array"}},{"title":"name","name":"getFilter"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":512,"column":4},"end":{"line":514,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L512-L514"},"params":[{"title":"param","description":"ID of a layer","type":{"type":"NameExpression","name":"string"},"name":"layer"}],"returns":[{"title":"returns","description":"filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)","type":{"type":"NameExpression","name":"Array"}}],"name":"getFilter","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","getFilter"]},{"description":"Get the value of a layout property in a given style layer.","tags":[{"title":"param","description":"ID of a layer","type":{"type":"NameExpression","name":"string"},"name":"layer"},{"title":"param","description":"name of a layout property","type":{"type":"NameExpression","name":"string"},"name":"name"},{"title":"param","description":"optional class specifier for the property","type":{"type":"OptionalType","expression":{"type":"NameExpression","name":"string"}},"name":"klass"},{"title":"returns","description":"value for the layout propery","type":{"type":"AllLiteral"}},{"title":"name","name":"getLayoutProperty"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":565,"column":4},"end":{"line":567,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L565-L567"},"params":[{"title":"param","description":"ID of a layer","type":{"type":"NameExpression","name":"string"},"name":"layer"},{"title":"param","description":"name of a layout property","type":{"type":"NameExpression","name":"string"},"name":"name"},{"title":"param","description":"optional class specifier for the property","type":{"type":"OptionalType","expression":{"type":"NameExpression","name":"string"}},"name":"klass"}],"returns":[{"title":"returns","description":"value for the layout propery","type":{"type":"AllLiteral"}}],"name":"getLayoutProperty","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","getLayoutProperty"]},{"description":"Get the Map's container as an HTML element","tags":[{"title":"returns","description":"container","type":{"type":"NameExpression","name":"HTMLElement"}},{"title":"name","name":"getContainer"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":573,"column":4},"end":{"line":575,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L573-L575"},"returns":[{"title":"returns","description":"container","type":{"type":"NameExpression","name":"HTMLElement"}}],"name":"getContainer","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","getContainer"]},{"description":"Get the Map's canvas as an HTML canvas","tags":[{"title":"returns","description":"canvas","type":{"type":"NameExpression","name":"HTMLElement"}},{"title":"name","name":"getCanvas"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":581,"column":4},"end":{"line":583,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L581-L583"},"returns":[{"title":"returns","description":"canvas","type":{"type":"NameExpression","name":"HTMLElement"}}],"name":"getCanvas","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","getCanvas"]},{"description":"Sets a map angle","tags":[{"title":"param","description":"The angle at which the camera is looking at the ground","type":{"type":"NameExpression","name":"number"},"name":"pitch"},{"title":"fires","description":"movestart"},{"title":"fires","description":"moveend"},{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}},{"title":"name","name":"setPitch"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":193,"column":4},"end":{"line":195,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L193-L195"},"params":[{"title":"param","description":"The angle at which the camera is looking at the ground","type":{"type":"NameExpression","name":"number"},"name":"pitch"}],"returns":[{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}}],"name":"setPitch","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","setPitch"]},{"description":"","tags":[{"title":"typedef","description":"[styleOptions]","type":{"type":"NameExpression","name":"Object"}},{"title":"name","name":"addClass"},{"title":"kind","kind":"typedef"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":234,"column":4},"end":{"line":238,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L234-L238"},"name":"addClass","kind":"typedef","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","addClass"]},{"description":"Adds a style class to a map","tags":[{"title":"param","description":"name of style class","type":{"type":"NameExpression","name":"string"},"name":"klass"},{"title":"param","description":null,"type":{"type":"NameExpression","name":"styleOptions"},"name":"options"},{"title":"fires","description":"change"},{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}},{"title":"name","name":"addClass"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":234,"column":4},"end":{"line":238,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L234-L238"},"params":[{"title":"param","description":"name of style class","type":{"type":"NameExpression","name":"string"},"name":"klass"},{"title":"param","description":null,"type":{"type":"NameExpression","name":"styleOptions"},"name":"options"}],"returns":[{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}}],"name":"addClass","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","addClass"]},{"description":"Add a source to the map style.","tags":[{"title":"param","description":"ID of the source. Must not be used by any existing source.","type":{"type":"NameExpression","name":"string"},"name":"id"},{"title":"param","description":"source specification, following the\n[Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)","type":{"type":"NameExpression","name":"Object"},"name":"source"},{"title":"fires","description":"source.add"},{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}},{"title":"name","name":"addSource"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":439,"column":4},"end":{"line":442,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L439-L442"},"params":[{"title":"param","description":"ID of the source. Must not be used by any existing source.","type":{"type":"NameExpression","name":"string"},"name":"id"},{"title":"param","description":"source specification, following the\n[Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)","type":{"type":"NameExpression","name":"Object"},"name":"source"}],"returns":[{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}}],"name":"addSource","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","addSource"]},{"description":"Add a layer to the map style. The layer will be inserted before the layer with\nID `before`, or appended if `before` is omitted.","tags":[{"title":"param","description":null,"type":{"type":"NameExpression","name":"Layer"},"name":"layer"},{"title":"param","description":"ID of an existing layer to insert before","type":{"type":"OptionalType","expression":{"type":"NameExpression","name":"string"}},"name":"before"},{"title":"fires","description":"layer.add"},{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}},{"title":"name","name":"addLayer"},{"title":"memberof","description":"Map"},{"title":"instance"}],"context":{"loc":{"start":{"line":474,"column":4},"end":{"line":478,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/map.js","code":"{\n\n    options: {\n        center: [0, 0],\n        zoom: 0,\n        bearing: 0,\n        pitch: 0,\n\n        minZoom: 0,\n        maxZoom: 20,\n\n        interactive: true,\n        hash: false,\n\n        attributionControl: true,\n\n        failIfMajorPerformanceCaveat: false\n    },\n\n    addControl: function(control) {\n        control.addTo(this);\n        return this;\n    },\n\n    /**\n     * Sets a map position\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @param {number} zoom Map zoom level\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setView: function(center, zoom, bearing, pitch) {\n        this.stop();\n\n        var tr = this.transform,\n            zoomChanged = tr.zoom !== +zoom,\n            bearingChanged = tr.bearing !== +bearing,\n            pitchChanged = tr.pitch !== +pitch;\n\n        tr.center = LatLng.convert(center);\n        tr.zoom = +zoom;\n        tr.bearing = +bearing;\n        tr.pitch = +pitch;\n\n        return this\n            .fire('movestart')\n            ._move(zoomChanged, bearingChanged, pitchChanged)\n            .fire('moveend');\n    },\n\n    /**\n     * Sets a map location\n     *\n     * @param {Array} center Latitude and longitude (passed as `[lat, lng]`)\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setCenter: function(center) {\n        this.setView(center, this.getZoom(), this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map zoom\n     *\n     * @param {number} zoom Map zoom level\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setZoom: function(zoom) {\n        this.setView(this.getCenter(), zoom, this.getBearing(), this.getPitch());\n    },\n\n    /**\n     * Sets a map rotation\n     *\n     * @param {number} bearing Map rotation bearing in degrees counter-clockwise from north\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setBearing: function(bearing) {\n        this.setView(this.getCenter(), this.getZoom(), bearing, this.getPitch());\n    },\n\n    /**\n     * Sets a map angle\n     *\n     * @param {number} pitch The angle at which the camera is looking at the ground\n     * @fires movestart\n     * @fires moveend\n     * @returns {Map} `this`\n     */\n    setPitch: function(pitch) {\n        this.setView(this.getCenter(), this.getZoom(), this.getBearing(), pitch);\n    },\n\n    /**\n     * Get the current view geographical point\n     * @returns {LatLng}\n     */\n    getCenter: function() { return this.transform.center; },\n\n    /**\n     * Get the current zoom\n     * @returns {number}\n     */\n    getZoom: function() { return this.transform.zoom; },\n\n    /**\n     * Get the current bearing in degrees\n     * @returns {number}\n     */\n    getBearing: function() { return this.transform.bearing; },\n\n    /**\n     * Get the current angle in degrees\n     * @returns {number}\n     */\n    getPitch: function() { return this.transform.pitch; },\n\n    /**\n     * @typedef {Object} [styleOptions]\n     * @param {Boolean} [styleOptions.transition=true]\n     */\n\n    /**\n     * Adds a style class to a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    addClass: function(klass, options) {\n        if (this._classes[klass]) return;\n        this._classes[klass] = true;\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Removes a style class from a map\n     *\n     * @param {string} klass name of style class\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    removeClass: function(klass, options) {\n        if (!this._classes[klass]) return;\n        delete this._classes[klass];\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Helper method to add more than one class\n     *\n     * @param {Array<string>} klasses An array of class names\n     * @param {styleOptions} options\n     * @fires change\n     * @returns {Map} `this`\n     */\n    setClasses: function(klasses, options) {\n        this._classes = {};\n        for (var i = 0; i < klasses.length; i++) {\n            this._classes[klasses[i]] = true;\n        }\n        if (this.style) this.style._cascade(this._classes, options);\n    },\n\n    /**\n     * Check whether a style class is active\n     *\n     * @param {string} klass Name of style class\n     * @returns {boolean}\n     */\n    hasClass: function(klass) {\n        return !!this._classes[klass];\n    },\n\n    /**\n     * Return an array of the current active style classes\n     *\n     * @returns {boolean}\n     */\n    getClasses: function() {\n        return Object.keys(this._classes);\n    },\n\n    /**\n     * Detect the map's new width and height and resize it.\n     *\n     * @returns {Map} `this`\n     */\n    resize: function() {\n        var width = 0, height = 0;\n\n        if (this._container) {\n            width = this._container.offsetWidth || 400;\n            height = this._container.offsetHeight || 300;\n        }\n\n        this._canvas.resize(width, height);\n\n        this.transform.width = width;\n        this.transform.height = height;\n        this.transform._constrain();\n\n        this.painter.resize(width, height);\n\n        return this\n            .fire('movestart')\n            ._move()\n            .fire('resize')\n            .fire('moveend');\n    },\n\n    /**\n     * Get the map's geographical bounds\n     *\n     * @returns {LatLngBounds}\n     */\n    getBounds: function() {\n        return new LatLngBounds(\n            this.transform.pointLocation(new Point(0, 0)),\n            this.transform.pointLocation(this.transform.size));\n    },\n\n    /**\n     * Get pixel coordinates (relative to map container) given a geographical location\n     *\n     * @param {LatLng} latlng\n     * @returns {Object} `x` and `y` coordinates\n     */\n    project: function(latlng) {\n        return this.transform.locationPoint(LatLng.convert(latlng));\n    },\n\n    /**\n     * Get geographical coordinates given pixel coordinates\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @returns {LatLng}\n     */\n    unproject: function(point) {\n        return this.transform.pointLocation(Point.convert(point));\n    },\n\n    /**\n     * Get all features at a point ([x, y])\n     *\n     * @param {Array<number>} point [x, y] pixel coordinates\n     * @param {Object} params\n     * @param {number} [params.radius=0] Optional. Radius in pixels to search in\n     * @param {string} params.layer Optional. Only return features from a given layer\n     * @param {string} params.type Optional. Either `raster` or `vector`\n     * @param {featuresAtCallback} callback function that returns the response\n     *\n     * @callback featuresAtCallback\n     * @param {Object|null} err Error _If any_\n     * @param {Array} features Displays a JSON array of features given the passed parameters of `featuresAt`\n     *\n     * @returns {Map} `this`\n     */\n    featuresAt: function(point, params, callback) {\n        var coord = this.transform.pointCoordinate(Point.convert(point));\n        this.style.featuresAt(coord, params, callback);\n        return this;\n    },\n\n    /**\n     * Replaces the map's style object\n     *\n     * @param {Object} style A style object formatted as JSON\n     * @returns {Map} `this`\n     */\n    setStyle: function(style) {\n        if (this.style) {\n            this.style\n                .off('load', this._onStyleLoad)\n                .off('error', this._forwardStyleEvent)\n                .off('change', this._onStyleChange)\n                .off('source.add', this._onSourceAdd)\n                .off('source.remove', this._onSourceRemove)\n                .off('source.load', this._onSourceUpdate)\n                .off('source.error', this._forwardSourceEvent)\n                .off('source.change', this._onSourceUpdate)\n                .off('layer.add', this._forwardLayerEvent)\n                .off('layer.remove', this._forwardLayerEvent)\n                .off('tile.add', this._forwardTileEvent)\n                .off('tile.remove', this._forwardTileEvent)\n                .off('tile.load', this.update)\n                .off('tile.error', this._forwardTileEvent)\n                ._remove();\n\n            this.off('rotate', this.style._redoPlacement);\n            this.off('pitch', this.style._redoPlacement);\n        }\n\n        if (!style) {\n            this.style = null;\n            return this;\n        } else if (style instanceof Style) {\n            this.style = style;\n        } else {\n            this.style = new Style(style, this.animationLoop);\n        }\n\n        this.style\n            .on('load', this._onStyleLoad)\n            .on('error', this._forwardStyleEvent)\n            .on('change', this._onStyleChange)\n            .on('source.add', this._onSourceAdd)\n            .on('source.remove', this._onSourceRemove)\n            .on('source.load', this._onSourceUpdate)\n            .on('source.error', this._forwardSourceEvent)\n            .on('source.change', this._onSourceUpdate)\n            .on('layer.add', this._forwardLayerEvent)\n            .on('layer.remove', this._forwardLayerEvent)\n            .on('tile.add', this._forwardTileEvent)\n            .on('tile.remove', this._forwardTileEvent)\n            .on('tile.load', this.update)\n            .on('tile.error', this._forwardTileEvent);\n\n        this.on('rotate', this.style._redoPlacement);\n        this.on('pitch', this.style._redoPlacement);\n\n        return this;\n    },\n\n    /**\n     * Add a source to the map style.\n     *\n     * @param {string} id ID of the source. Must not be used by any existing source.\n     * @param {Object} source source specification, following the\n     * [Mapbox GL Style Reference](https://www.mapbox.com/mapbox-gl-style-spec/#sources)\n     * @fires source.add\n     * @returns {Map} `this`\n     */\n    addSource: function(id, source) {\n        this.style.addSource(id, source);\n        return this;\n    },\n\n    /**\n     * Remove an existing source from the map style.\n     *\n     * @param {string} id ID of the source to remove\n     * @fires source.remove\n     * @returns {Map} `this`\n     */\n    removeSource: function(id) {\n        this.style.removeSource(id);\n        return this;\n    },\n\n    /**\n     * Return the style source object with the given `id`.\n     *\n     * @param {string} id source ID\n     * @returns {Object}\n     */\n    getSource: function(id) {\n        return this.style.getSource(id);\n    },\n\n    /**\n     * Add a layer to the map style. The layer will be inserted before the layer with\n     * ID `before`, or appended if `before` is omitted.\n     * @param {Layer} layer\n     * @param {string=} before  ID of an existing layer to insert before\n     * @fires layer.add\n     * @returns {Map} `this`\n     */\n    addLayer: function(layer, before) {\n        this.style.addLayer(layer, before);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Remove the layer with the given `id` from the map. Any layers which refer to the\n     * specified layer via a `ref` property are also removed.\n     *\n     * @param {string} id\n     * @fires layer.remove\n     * @returns {Map} this\n     */\n    removeLayer: function(id) {\n        this.style.removeLayer(id);\n        this.style._cascade(this._classes);\n        return this;\n    },\n\n    /**\n     * Set the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {Array} filter filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     * @returns {Map} `this`\n     */\n    setFilter: function(layer, filter) {\n        this.style.setFilter(layer, filter);\n        return this;\n    },\n\n    /**\n     * Get the filter for a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @returns {Array} filter specification, as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#filter)\n     */\n    getFilter: function(layer) {\n        return this.style.getFilter(layer);\n    },\n\n    /**\n     * Set the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {*} value value for the paint propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @param {string=} klass optional class specifier for the property\n     * @returns {Map} `this`\n     */\n    setPaintProperty: function(layer, name, value, klass) {\n        this.style.setPaintProperty(layer, name, value, klass);\n        this.style._cascade(this._classes);\n        this.update(true);\n        return this;\n    },\n\n    /**\n     * Get the value of a paint property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a paint property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the paint propery\n     */\n    getPaintProperty: function(layer, name, klass) {\n        return this.style.getPaintProperty(layer, name, klass);\n    },\n\n    /**\n     * Set the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {*} value value for the layout propery; must have the type appropriate for the property as defined in the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)\n     * @returns {Map} `this`\n     */\n    setLayoutProperty: function(layer, name, value) {\n        this.style.setLayoutProperty(layer, name, value);\n        return this;\n    },\n\n    /**\n     * Get the value of a layout property in a given style layer.\n     *\n     * @param {string} layer ID of a layer\n     * @param {string} name name of a layout property\n     * @param {string=} klass optional class specifier for the property\n     * @returns {*} value for the layout propery\n     */\n    getLayoutProperty: function(layer, name) {\n        return this.style.getLayoutProperty(layer, name);\n    },\n\n    /**\n     * Get the Map's container as an HTML element\n     * @returns {HTMLElement} container\n     */\n    getContainer: function() {\n        return this._container;\n    },\n\n    /**\n     * Get the Map's canvas as an HTML canvas\n     * @returns {HTMLElement} canvas\n     */\n    getCanvas: function() {\n        return this._canvas.getElement();\n    },\n\n    _move: function(zoom, rotate, pitch) {\n\n        this.update(zoom).fire('move');\n\n        if (zoom) this.fire('zoom');\n        if (rotate) this.fire('rotate');\n        if (pitch) this.fire('pitch');\n\n        return this;\n    },\n\n    // map setup code\n    _setupContainer: function() {\n        var id = this.options.container;\n        var container = this._container = typeof id === 'string' ? document.getElementById(id) : id;\n        if (container) container.classList.add('mapboxgl-map');\n        this._canvas = new Canvas(this, container);\n    },\n\n    _setupControlPos: function() {\n        var corners = this._controlCorners = {};\n        var prefix = 'mapboxgl-ctrl-';\n        var container = this.getContainer();\n\n        function createCorner(pos) {\n            var className = prefix + pos;\n            corners[pos] = DOM.create('div', className, container);\n        }\n\n        if (container && typeof document === 'object') {\n            createCorner('top-left');\n            createCorner('top-right');\n            createCorner('bottom-left');\n            createCorner('bottom-right');\n        }\n    },\n\n    _setupPainter: function() {\n        var gl = this._canvas.getWebGLContext(this.options.failIfMajorPerformanceCaveat);\n\n        if (!gl) {\n            console.error('Failed to initialize WebGL');\n            return;\n        }\n\n        this.painter = new GLPainter(gl, this.transform);\n    },\n\n    _contextLost: function(event) {\n        event.preventDefault();\n        if (this._frameId) {\n            browser.cancelFrame(this._frameId);\n        }\n    },\n\n    _contextRestored: function() {\n        this._setupPainter();\n        this.resize();\n        this.update();\n    },\n\n    /**\n     * Is this map fully loaded? If the style isn't loaded\n     * or it has a change to the sources or style that isn't\n     * propagated to its style, return false.\n     *\n     * @returns {boolean} whether the map is loaded\n     */\n    loaded: function() {\n        if (this._styleDirty || this._sourcesDirty)\n            return false;\n        if (this.style && !this.style.loaded())\n            return false;\n        return true;\n    },\n\n    /**\n     * Update this map's style and re-render the map.\n     *\n     * @param {Object} updateStyle new style\n     * @returns {Map} this\n     */\n    update: function(updateStyle) {\n        if (!this.style) return this;\n\n        this._styleDirty = this._styleDirty || updateStyle;\n        this._sourcesDirty = true;\n\n        this._rerender();\n\n        return this;\n    },\n\n    /**\n     * Call when a (re-)render of the map is required, e.g. when the\n     * user panned or zoomed,f or new data is available.\n     * @returns {Map} this\n     */\n    render: function() {\n        if (this.style && this._styleDirty) {\n            this._styleDirty = false;\n            this.style._recalculate(this.transform.zoom);\n        }\n\n        if (this.style && this._sourcesDirty && !this._sourcesDirtyTimeout) {\n            this._sourcesDirty = false;\n            this._sourcesDirtyTimeout = setTimeout(function() {\n                this._sourcesDirtyTimeout = null;\n            }.bind(this), 50);\n            this.style._updateSources(this.transform);\n        }\n\n        this.painter.render(this.style, {\n            debug: this.debug,\n            vertices: this.vertices,\n            rotating: this.rotating,\n            zooming: this.zooming\n        });\n\n        this.fire('render');\n\n        if (this.loaded() && !this._loaded) {\n            this._loaded = true;\n            this.fire('load');\n        }\n\n        this._frameId = null;\n\n        if (!this.animationLoop.stopped()) {\n            this._styleDirty = true;\n        }\n\n        if (this._sourcesDirty || this._repaint || !this.animationLoop.stopped()) {\n            this._rerender();\n        }\n\n        return this;\n    },\n\n    /**\n     * Destroys the map's underlying resources, including web workers.\n     * @returns {Map} this\n     */\n    remove: function() {\n        if (this._hash) this._hash.remove();\n        browser.cancelFrame(this._frameId);\n        clearTimeout(this._sourcesDirtyTimeout);\n        this.setStyle(null);\n        return this;\n    },\n\n    _rerender: function() {\n        if (this.style && !this._frameId) {\n            this._frameId = browser.frame(this.render);\n        }\n    },\n\n    _forwardStyleEvent: function(e) {\n        this.fire('style.' + e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardSourceEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardLayerEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _forwardTileEvent: function(e) {\n        this.fire(e.type, util.extend({style: e.target}, e));\n    },\n\n    _onStyleLoad: function(e) {\n        this.style._cascade(this._classes, {transition: false});\n        this._forwardStyleEvent(e);\n    },\n\n    _onStyleChange: function(e) {\n        this.update(true);\n        this._forwardStyleEvent(e);\n    },\n\n    _onSourceAdd: function(e) {\n        var source = e.source;\n        if (source.onAdd)\n            source.onAdd(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceRemove: function(e) {\n        var source = e.source;\n        if (source.onRemove)\n            source.onRemove(this);\n        this._forwardSourceEvent(e);\n    },\n\n    _onSourceUpdate: function(e) {\n        this.update();\n        this._forwardSourceEvent(e);\n    }\n}","path":"js/ui/map.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/map.js#L474-L478"},"params":[{"title":"param","description":null,"type":{"type":"NameExpression","name":"Layer"},"name":"layer"},{"title":"param","description":"ID of an existing layer to insert before","type":{"type":"OptionalType","expression":{"type":"NameExpression","name":"string"}},"name":"before"}],"returns":[{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"Map"}}],"name":"addLayer","memberof":"Map","scope":"instance","members":{"instance":[],"static":[]},"path":["Map","addLayer"]}],"static":[]},"path":["Map"]},{"description":"Create a GeoJSON data source instance given an options object","tags":[{"title":"class","description":null,"type":null,"name":"GeoJSONSource"},{"title":"name","name":"GeoJSONSource"},{"title":"kind","kind":"class"}],"context":{"loc":{"start":{"line":35,"column":0},"end":{"line":53,"column":1}},"file":"/Users/tmcw/src/mapbox-gl-js/js/source/geojson_source.js","code":"'use strict';\n\nvar util = require('../util/util');\nvar Evented = require('../util/evented');\nvar TilePyramid = require('./tile_pyramid');\nvar Source = require('./source');\n\nmodule.exports = GeoJSONSource;\n\n/**\n * Create a GeoJSON data source instance given an options object\n * @class GeoJSONSource\n * @param {Object} [options]\n * @param {Object|String} options.data A GeoJSON data object or URL to it. The latter is preferable in case of large GeoJSON files.\n * @param {Number} [options.maxzoom=14] Maximum zoom to preserve detail at.\n * @example\n * var sourceObj = new mapboxgl.GeoJSONSource({\n *    data: {\n *        \"type\": \"FeatureCollection\",\n *        \"features\": [{\n *            \"type\": \"Feature\",\n *            \"geometry\": {\n *                \"type\": \"Point\",\n *                \"coordinates\": [\n *                    -76.53063297271729,\n *                    39.18174077994108\n *                ]\n *            }\n *        }]\n *    }\n * });\n * map.addSource('some id', sourceObj); // add\n * map.removeSource('some id');  // remove\n */\nfunction GeoJSONSource(options) {\n    options = options || {};\n\n    this._data = options.data;\n\n    if (options.maxzoom !== undefined) this.maxzoom = options.maxzoom;\n\n    this._pyramid = new TilePyramid({\n        tileSize: 512,\n        minzoom: this.minzoom,\n        maxzoom: this.maxzoom,\n        cacheSize: 20,\n        load: this._loadTile.bind(this),\n        abort: this._abortTile.bind(this),\n        unload: this._unloadTile.bind(this),\n        add: this._addTile.bind(this),\n        remove: this._removeTile.bind(this)\n    });\n}\n\nGeoJSONSource.prototype = util.inherit(Evented, /** @lends GeoJSONSource.prototype */{\n    minzoom: 0,\n    maxzoom: 14,\n    _dirty: true,\n\n    /**\n     * Update source geojson data and rerender map\n     *\n     * @param {Object|String} data A GeoJSON data object or URL to it. The latter is preferable in case of large GeoJSON files.\n     */\n    setData: function(data) {\n        this._data = data;\n        this._dirty = true;\n\n        this.fire('change');\n\n        if (this.map)\n            this.update(this.map.transform);\n\n        return this;\n    },\n\n    onAdd: function(map) {\n        this.map = map;\n    },\n\n    loaded: function() {\n        return this._loaded && this._pyramid.loaded();\n    },\n\n    update: function(transform) {\n        if (this._dirty) {\n            this._updateData();\n        }\n\n        if (this._loaded) {\n            this._pyramid.update(this.used, transform);\n        }\n    },\n\n    reload: function() {\n        this._pyramid.reload();\n    },\n\n    render: Source._renderTiles,\n    featuresAt: Source._vectorFeaturesAt,\n\n    _updateData: function() {\n        this._dirty = false;\n\n        this.workerID = this.dispatcher.send('parse geojson', {\n            data: this._data,\n            tileSize: 512,\n            source: this.id,\n            maxZoom: this.maxzoom\n        }, function(err) {\n\n            if (err) {\n                this.fire('error', {error: err});\n                return;\n            }\n            this._loaded = true;\n            this._pyramid.reload();\n\n            this.fire('change');\n        }.bind(this));\n    },\n\n    _loadTile: function(tile) {\n        var overscaling = tile.zoom > this.maxzoom ? Math.pow(2, tile.zoom - this.maxzoom) : 1;\n        var params = {\n            uid: tile.uid,\n            id: tile.id,\n            zoom: tile.zoom,\n            maxZoom: this.maxzoom,\n            tileSize: 512,\n            source: this.id,\n            overscaling: overscaling,\n            angle: this.map.transform.angle,\n            pitch: this.map.transform.pitch,\n            collisionDebug: this.map.collisionDebug\n        };\n\n        tile.workerID = this.dispatcher.send('load geojson tile', params, function(err, data) {\n\n            tile.unloadVectorData(this.map.painter);\n\n            if (tile.aborted)\n                return;\n\n            if (err) {\n                this.fire('tile.error', {tile: tile});\n                return;\n            }\n\n            tile.loadVectorData(data);\n            this.fire('tile.load', {tile: tile});\n\n        }.bind(this), this.workerID);\n    },\n\n    _abortTile: function(tile) {\n        tile.aborted = true;\n    },\n\n    _addTile: function(tile) {\n        this.fire('tile.add', {tile: tile});\n    },\n\n    _removeTile: function(tile) {\n        this.fire('tile.remove', {tile: tile});\n    },\n\n    _unloadTile: function(tile) {\n        tile.unloadVectorData(this.map.painter);\n        this.glyphAtlas.removeGlyphs(tile.uid);\n        this.dispatcher.send('remove tile', { uid: tile.uid, source: this.id }, null, tile.workerID);\n    }\n});","path":"js/source/geojson_source.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/source/geojson_source.js#L35-L53"},"name":"GeoJSONSource","kind":"class","members":{"instance":[{"description":"Update source geojson data and rerender map","tags":[{"title":"param","description":"A GeoJSON data object or URL to it. The latter is preferable in case of large GeoJSON files.","type":{"type":"UnionType","elements":[{"type":"NameExpression","name":"Object"},{"type":"NameExpression","name":"String"}]},"name":"data"},{"title":"name","name":"setData"},{"title":"memberof","description":"GeoJSONSource"},{"title":"instance"}],"context":{"loc":{"start":{"line":65,"column":4},"end":{"line":75,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/source/geojson_source.js","code":"{\n    minzoom: 0,\n    maxzoom: 14,\n    _dirty: true,\n\n    /**\n     * Update source geojson data and rerender map\n     *\n     * @param {Object|String} data A GeoJSON data object or URL to it. The latter is preferable in case of large GeoJSON files.\n     */\n    setData: function(data) {\n        this._data = data;\n        this._dirty = true;\n\n        this.fire('change');\n\n        if (this.map)\n            this.update(this.map.transform);\n\n        return this;\n    },\n\n    onAdd: function(map) {\n        this.map = map;\n    },\n\n    loaded: function() {\n        return this._loaded && this._pyramid.loaded();\n    },\n\n    update: function(transform) {\n        if (this._dirty) {\n            this._updateData();\n        }\n\n        if (this._loaded) {\n            this._pyramid.update(this.used, transform);\n        }\n    },\n\n    reload: function() {\n        this._pyramid.reload();\n    },\n\n    render: Source._renderTiles,\n    featuresAt: Source._vectorFeaturesAt,\n\n    _updateData: function() {\n        this._dirty = false;\n\n        this.workerID = this.dispatcher.send('parse geojson', {\n            data: this._data,\n            tileSize: 512,\n            source: this.id,\n            maxZoom: this.maxzoom\n        }, function(err) {\n\n            if (err) {\n                this.fire('error', {error: err});\n                return;\n            }\n            this._loaded = true;\n            this._pyramid.reload();\n\n            this.fire('change');\n        }.bind(this));\n    },\n\n    _loadTile: function(tile) {\n        var overscaling = tile.zoom > this.maxzoom ? Math.pow(2, tile.zoom - this.maxzoom) : 1;\n        var params = {\n            uid: tile.uid,\n            id: tile.id,\n            zoom: tile.zoom,\n            maxZoom: this.maxzoom,\n            tileSize: 512,\n            source: this.id,\n            overscaling: overscaling,\n            angle: this.map.transform.angle,\n            pitch: this.map.transform.pitch,\n            collisionDebug: this.map.collisionDebug\n        };\n\n        tile.workerID = this.dispatcher.send('load geojson tile', params, function(err, data) {\n\n            tile.unloadVectorData(this.map.painter);\n\n            if (tile.aborted)\n                return;\n\n            if (err) {\n                this.fire('tile.error', {tile: tile});\n                return;\n            }\n\n            tile.loadVectorData(data);\n            this.fire('tile.load', {tile: tile});\n\n        }.bind(this), this.workerID);\n    },\n\n    _abortTile: function(tile) {\n        tile.aborted = true;\n    },\n\n    _addTile: function(tile) {\n        this.fire('tile.add', {tile: tile});\n    },\n\n    _removeTile: function(tile) {\n        this.fire('tile.remove', {tile: tile});\n    },\n\n    _unloadTile: function(tile) {\n        tile.unloadVectorData(this.map.painter);\n        this.glyphAtlas.removeGlyphs(tile.uid);\n        this.dispatcher.send('remove tile', { uid: tile.uid, source: this.id }, null, tile.workerID);\n    }\n}","path":"js/source/geojson_source.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/source/geojson_source.js#L65-L75"},"params":[{"title":"param","description":"A GeoJSON data object or URL to it. The latter is preferable in case of large GeoJSON files.","type":{"type":"UnionType","elements":[{"type":"NameExpression","name":"Object"},{"type":"NameExpression","name":"String"}]},"name":"data"}],"name":"setData","memberof":"GeoJSONSource","scope":"instance","members":{"instance":[],"static":[]},"path":["GeoJSONSource","setData"]}],"static":[]},"path":["GeoJSONSource"]},{"description":"Creates a navigation control with zoom buttons and a compass","tags":[{"title":"class","description":null,"type":null,"name":"Navigation"},{"title":"name","name":"Navigation"},{"title":"kind","kind":"class"}],"context":{"loc":{"start":{"line":17,"column":0},"end":{"line":19,"column":1}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/control/navigation.js","code":"'use strict';\n\nvar Control = require('./control');\nvar DOM = require('../../util/dom');\nvar util = require('../../util/util');\n\nmodule.exports = Navigation;\n\n/**\n * Creates a navigation control with zoom buttons and a compass\n * @class Navigation\n * @param {Object} [options]\n * @param {String} [options.position=top-right] A string indicating the control's position on the map. Options are `top-right`, `top-left`, `bottom-right`, `bottom-left`\n * @example\n * map.addControl(new mapboxgl.Navigation({position: 'top-left'})); // position is optional\n */\nfunction Navigation(options) {\n    util.setOptions(this, options);\n}\n\nNavigation.prototype = util.inherit(Control, {\n    options: {\n        position: 'top-right'\n    },\n\n    onAdd: function(map) {\n        var className = 'mapboxgl-ctrl';\n\n        var container = this._container = DOM.create('div', className + '-group', map.getContainer());\n\n        this._zoomInButton = this._createButton(className + '-icon ' + className + '-zoom-in', map.zoomIn.bind(map));\n        this._zoomOutButton = this._createButton(className + '-icon ' + className + '-zoom-out', map.zoomOut.bind(map));\n        this._compass = this._createButton(className + '-compass', map.resetNorth.bind(map));\n\n        var compassCanvas = this._compassCanvas = DOM.create('canvas', className + '-compass-canvas', this._compass);\n        compassCanvas.style.cssText = 'width:26px; height:26px;';\n        compassCanvas.width = 26 * 2;\n        compassCanvas.height = 26 * 2;\n\n        this._compass.addEventListener('mousedown', this._onCompassDown.bind(this));\n        this._onCompassMove = this._onCompassMove.bind(this);\n        this._onCompassUp = this._onCompassUp.bind(this);\n\n        this._compassCtx = compassCanvas.getContext('2d');\n\n        map.on('rotate', this._drawNorth.bind(this));\n        this._drawNorth();\n\n        return container;\n    },\n\n    _onCompassDown: function(e) {\n        DOM.disableDrag();\n\n        document.addEventListener('mousemove', this._onCompassMove);\n        document.addEventListener('mouseup', this._onCompassUp);\n        this._prevX = e.screenX;\n\n        e.stopPropagation();\n    },\n\n    _onCompassMove: function(e) {\n        var x = e.screenX,\n            d = x < 2 ? -5 : // left edge of the screen, continue rotating\n                x > window.screen.width - 2 ? 5 : // right edge\n                (x - this._prevX) / 4;\n\n        this._map.setBearing(this._map.getBearing() - d);\n        this._prevX = e.screenX;\n        this._moved = true;\n\n        e.preventDefault();\n    },\n\n    _onCompassUp: function() {\n        document.removeEventListener('mousemove', this._onCompassMove);\n        document.removeEventListener('mouseup', this._onCompassUp);\n        DOM.enableDrag();\n\n        if (this._moved) {\n            this._moved = false;\n            DOM.suppressClick();\n        }\n    },\n\n    _createButton: function(className, fn) {\n        var a = DOM.create('button', className, this._container);\n        a.addEventListener('click', function() { fn(); });\n        return a;\n    },\n\n    _drawNorth: function() {\n        var rad = 20,\n            width = 8,\n            center = 26,\n            angle = this._map.transform.angle + (Math.PI / 2),\n            ctx = this._compassCtx;\n\n        this._compassCanvas.width = this._compassCanvas.width;\n\n        ctx.translate(center, center);\n        ctx.rotate(angle);\n\n        ctx.beginPath();\n        ctx.fillStyle = '#000';\n        ctx.lineTo(0, -width);\n        ctx.lineTo(-rad, 0);\n        ctx.lineTo(0, width);\n        ctx.fill();\n\n        ctx.beginPath();\n        ctx.fillStyle = '#bbb';\n        ctx.moveTo(0, 0);\n        ctx.lineTo(0, width);\n        ctx.lineTo(rad, 0);\n        ctx.lineTo(0, -width);\n        ctx.fill();\n\n        ctx.beginPath();\n        ctx.strokeStyle = '#fff';\n        ctx.lineWidth = 4;\n        ctx.moveTo(0, -width);\n        ctx.lineTo(0, width);\n        ctx.stroke();\n    }\n});","path":"js/ui/control/navigation.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/control/navigation.js#L17-L19"},"name":"Navigation","kind":"class","members":{"instance":[],"static":[]},"path":["Navigation"]},{"description":"A base class for map-related interface elements.","tags":[{"title":"class","description":null,"type":null,"name":"Control"},{"title":"name","name":"Control"},{"title":"kind","kind":"class"}],"context":{"loc":{"start":{"line":10,"column":0},"end":{"line":10,"column":21}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/control/control.js","code":"'use strict';\n\nmodule.exports = Control;\n\n/**\n * A base class for map-related interface elements.\n *\n * @class Control\n */\nfunction Control() {}\n\nControl.prototype = {\n    /**\n     * Add this control to the map, returning the control itself\n     * for chaining. This will insert the control's DOM element into\n     * the map's DOM element if the control has a `position` specified.\n     *\n     * @param {Map} map\n     * @returns {Control} this\n     */\n    addTo: function(map) {\n        this._map = map;\n        var container = this._container = this.onAdd(map);\n        if (this.options && this.options.position) {\n            var pos = this.options.position;\n            var corner = map._controlCorners[pos];\n            container.className += ' mapboxgl-ctrl';\n            if (pos.indexOf('bottom') !== -1) {\n                corner.insertBefore(container, corner.firstChild);\n            } else {\n                corner.appendChild(container);\n            }\n        }\n\n        return this;\n    },\n\n    /**\n     * Remove this control from the map it has been added to.\n     *\n     * @returns {Control} this\n     */\n    remove: function() {\n        this._container.parentNode.removeChild(this._container);\n        if (this.onRemove) this.onRemove(this._map);\n        this._map = null;\n        return this;\n    }\n};","path":"js/ui/control/control.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/control/control.js#L10-L10"},"name":"Control","kind":"class","members":{"instance":[{"description":"Remove this control from the map it has been added to.","tags":[{"title":"returns","description":"this","type":{"type":"NameExpression","name":"Control"}},{"title":"name","name":"remove"},{"title":"memberof","description":"Control"},{"title":"instance"}],"context":{"loc":{"start":{"line":43,"column":4},"end":{"line":48,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/control/control.js","code":"{\n    /**\n     * Add this control to the map, returning the control itself\n     * for chaining. This will insert the control's DOM element into\n     * the map's DOM element if the control has a `position` specified.\n     *\n     * @param {Map} map\n     * @returns {Control} this\n     */\n    addTo: function(map) {\n        this._map = map;\n        var container = this._container = this.onAdd(map);\n        if (this.options && this.options.position) {\n            var pos = this.options.position;\n            var corner = map._controlCorners[pos];\n            container.className += ' mapboxgl-ctrl';\n            if (pos.indexOf('bottom') !== -1) {\n                corner.insertBefore(container, corner.firstChild);\n            } else {\n                corner.appendChild(container);\n            }\n        }\n\n        return this;\n    },\n\n    /**\n     * Remove this control from the map it has been added to.\n     *\n     * @returns {Control} this\n     */\n    remove: function() {\n        this._container.parentNode.removeChild(this._container);\n        if (this.onRemove) this.onRemove(this._map);\n        this._map = null;\n        return this;\n    }\n}","path":"js/ui/control/control.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/control/control.js#L43-L48"},"returns":[{"title":"returns","description":"this","type":{"type":"NameExpression","name":"Control"}}],"name":"remove","memberof":"Control","scope":"instance","members":{"instance":[],"static":[]},"path":["Control","remove"]},{"description":"Add this control to the map, returning the control itself\nfor chaining. This will insert the control's DOM element into\nthe map's DOM element if the control has a `position` specified.","tags":[{"title":"param","description":null,"type":{"type":"NameExpression","name":"Map"},"name":"map"},{"title":"returns","description":"this","type":{"type":"NameExpression","name":"Control"}},{"title":"name","name":"addTo"},{"title":"memberof","description":"Control"},{"title":"instance"}],"context":{"loc":{"start":{"line":21,"column":4},"end":{"line":36,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/control/control.js","code":"{\n    /**\n     * Add this control to the map, returning the control itself\n     * for chaining. This will insert the control's DOM element into\n     * the map's DOM element if the control has a `position` specified.\n     *\n     * @param {Map} map\n     * @returns {Control} this\n     */\n    addTo: function(map) {\n        this._map = map;\n        var container = this._container = this.onAdd(map);\n        if (this.options && this.options.position) {\n            var pos = this.options.position;\n            var corner = map._controlCorners[pos];\n            container.className += ' mapboxgl-ctrl';\n            if (pos.indexOf('bottom') !== -1) {\n                corner.insertBefore(container, corner.firstChild);\n            } else {\n                corner.appendChild(container);\n            }\n        }\n\n        return this;\n    },\n\n    /**\n     * Remove this control from the map it has been added to.\n     *\n     * @returns {Control} this\n     */\n    remove: function() {\n        this._container.parentNode.removeChild(this._container);\n        if (this.onRemove) this.onRemove(this._map);\n        this._map = null;\n        return this;\n    }\n}","path":"js/ui/control/control.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/control/control.js#L21-L36"},"params":[{"title":"param","description":null,"type":{"type":"NameExpression","name":"Map"},"name":"map"}],"returns":[{"title":"returns","description":"this","type":{"type":"NameExpression","name":"Control"}}],"name":"addTo","memberof":"Control","scope":"instance","members":{"instance":[],"static":[]},"path":["Control","addTo"]}],"static":[]},"path":["Control"]},{"description":"Creates an attribution control","tags":[{"title":"class","description":null,"type":null,"name":"Attribution"},{"title":"augments","description":null,"type":null,"name":"Control"},{"title":"example","description":"map.addControl(new mapboxgl.Attribution());"},{"title":"name","name":"Attribution"},{"title":"kind","kind":"class"}],"context":{"loc":{"start":{"line":16,"column":0},"end":{"line":16,"column":25}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/control/attribution.js","code":"'use strict';\n\nvar Control = require('./control');\nvar DOM = require('../../util/dom');\nvar util = require('../../util/util');\n\nmodule.exports = Attribution;\n\n/**\n * Creates an attribution control\n * @class Attribution\n * @augments Control\n * @example\n * map.addControl(new mapboxgl.Attribution());\n */\nfunction Attribution() {}\n\nAttribution.prototype = util.inherit(Control, {\n    options: {\n        position: 'bottom-right'\n    },\n\n    onAdd: function(map) {\n        var className = 'mapboxgl-ctrl-attrib',\n            container = this._container = DOM.create('div', className, map.getContainer());\n\n        this._update();\n        map.on('source.load', this._update.bind(this));\n        map.on('source.change', this._update.bind(this));\n        map.on('source.remove', this._update.bind(this));\n        map.on('moveend', this._updateEditLink.bind(this));\n\n        return container;\n    },\n\n    _update: function() {\n        var attributions = [];\n\n        if (this._map.style) {\n            for (var id in this._map.style.sources) {\n                var source = this._map.style.sources[id];\n                if (source.attribution && attributions.indexOf(source.attribution) < 0) {\n                    attributions.push(source.attribution);\n                }\n            }\n        }\n\n        this._container.innerHTML = attributions.join(' | ');\n        this._editLink = this._container.getElementsByClassName('mapbox-improve-map')[0];\n        this._updateEditLink();\n    },\n\n    _updateEditLink: function() {\n        if (this._editLink) {\n            var center = this._map.getCenter();\n            this._editLink.href = 'https://www.mapbox.com/map-feedback/#/' +\n                    center.lng + '/' + center.lat + '/' + Math.round(this._map.getZoom() + 1);\n        }\n    }\n});","path":"js/ui/control/attribution.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/control/attribution.js#L16-L16"},"augments":[{"title":"augments","description":null,"type":null,"name":"Control"}],"examples":["map.addControl(<span class=\"hljs-keyword\">new</span> mapboxgl.Attribution());"],"name":"Attribution","kind":"class","members":{"instance":[],"static":[]},"path":["Attribution"]},{"description":"Create a latitude, longitude object from a given latitude and longitude pair in degrees.","tags":[{"title":"class","description":null,"type":null,"name":"LatLng"},{"title":"classdesc","description":"A representation of a latitude and longitude point, in degrees."},{"title":"param","description":"latitude","type":{"type":"NameExpression","name":"number"},"name":"lat"},{"title":"param","description":"longitude","type":{"type":"NameExpression","name":"number"},"name":"lng"},{"title":"example","description":"var latlng = new mapboxgl.LatLng(37.76, -122.44);"},{"title":"name","name":"LatLng"},{"title":"kind","kind":"class"}],"context":{"loc":{"start":{"line":18,"column":0},"end":{"line":24,"column":1}},"file":"/Users/tmcw/src/mapbox-gl-js/js/geo/lat_lng.js","code":"'use strict';\n\nmodule.exports = LatLng;\n\nvar wrap = require('../util/util').wrap;\n\n/**\n * Create a latitude, longitude object from a given latitude and longitude pair in degrees.\n *\n * @class LatLng\n * @classdesc A representation of a latitude and longitude point, in degrees.\n * @param {number} lat latitude\n * @param {number} lng longitude\n * @example\n * var latlng = new mapboxgl.LatLng(37.76, -122.44);\n *\n */\nfunction LatLng(lat, lng) {\n    if (isNaN(lat) || isNaN(lng)) {\n        throw new Error('Invalid LatLng object: (' + lat + ', ' + lng + ')');\n    }\n    this.lat = +lat;\n    this.lng = +lng;\n}\n\n/**\n * Return a new `LatLng` object whose longitude is wrapped to the range (-180, 180).\n *\n * @returns {LatLng} wrapped LatLng object\n */\nLatLng.prototype.wrap = function () {\n    return new LatLng(this.lat, wrap(this.lng, -180, 180));\n};\n\n/**\n * Convert an array to a `LatLng` object, or return an existing `LatLng` object\n * unchanged.\n *\n * @param {Array<number>|LatLng} input `input` to convert\n * @returns {LatLng} LatLng object or original input\n */\nLatLng.convert = function (input) {\n    if (input instanceof LatLng) {\n        return input;\n    }\n    if (Array.isArray(input)) {\n        return new LatLng(input[0], input[1]);\n    }\n    return input;\n};","path":"js/geo/lat_lng.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/geo/lat_lng.js#L18-L24"},"classdesc":"A representation of a latitude and longitude point, in degrees.","params":[{"title":"param","description":"latitude","type":{"type":"NameExpression","name":"number"},"name":"lat"},{"title":"param","description":"longitude","type":{"type":"NameExpression","name":"number"},"name":"lng"}],"examples":["<span class=\"hljs-keyword\">var</span> latlng = <span class=\"hljs-keyword\">new</span> mapboxgl.LatLng(<span class=\"hljs-number\">37.76</span>, -<span class=\"hljs-number\">122.44</span>);"],"name":"LatLng","kind":"class","members":{"instance":[{"description":"Return a new `LatLng` object whose longitude is wrapped to the range (-180, 180).","tags":[{"title":"returns","description":"wrapped LatLng object","type":{"type":"NameExpression","name":"LatLng"}},{"title":"name","name":"wrap"},{"title":"memberof","description":"LatLng"},{"title":"instance"}],"context":{"loc":{"start":{"line":31,"column":0},"end":{"line":33,"column":2}},"file":"/Users/tmcw/src/mapbox-gl-js/js/geo/lat_lng.js","code":"'use strict';\n\nmodule.exports = LatLng;\n\nvar wrap = require('../util/util').wrap;\n\n/**\n * Create a latitude, longitude object from a given latitude and longitude pair in degrees.\n *\n * @class LatLng\n * @classdesc A representation of a latitude and longitude point, in degrees.\n * @param {number} lat latitude\n * @param {number} lng longitude\n * @example\n * var latlng = new mapboxgl.LatLng(37.76, -122.44);\n *\n */\nfunction LatLng(lat, lng) {\n    if (isNaN(lat) || isNaN(lng)) {\n        throw new Error('Invalid LatLng object: (' + lat + ', ' + lng + ')');\n    }\n    this.lat = +lat;\n    this.lng = +lng;\n}\n\n/**\n * Return a new `LatLng` object whose longitude is wrapped to the range (-180, 180).\n *\n * @returns {LatLng} wrapped LatLng object\n */\nLatLng.prototype.wrap = function () {\n    return new LatLng(this.lat, wrap(this.lng, -180, 180));\n};\n\n/**\n * Convert an array to a `LatLng` object, or return an existing `LatLng` object\n * unchanged.\n *\n * @param {Array<number>|LatLng} input `input` to convert\n * @returns {LatLng} LatLng object or original input\n */\nLatLng.convert = function (input) {\n    if (input instanceof LatLng) {\n        return input;\n    }\n    if (Array.isArray(input)) {\n        return new LatLng(input[0], input[1]);\n    }\n    return input;\n};","path":"js/geo/lat_lng.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/geo/lat_lng.js#L31-L33"},"returns":[{"title":"returns","description":"wrapped LatLng object","type":{"type":"NameExpression","name":"LatLng"}}],"name":"wrap","memberof":"LatLng","scope":"instance","members":{"instance":[],"static":[]},"path":["LatLng","wrap"]}],"static":[{"description":"Convert an array to a `LatLng` object, or return an existing `LatLng` object\nunchanged.","tags":[{"title":"param","description":"`input` to convert","type":{"type":"UnionType","elements":[{"type":"TypeApplication","expression":{"type":"NameExpression","name":"Array"},"applications":[{"type":"NameExpression","name":"number"}]},{"type":"NameExpression","name":"LatLng"}]},"name":"input"},{"title":"returns","description":"LatLng object or original input","type":{"type":"NameExpression","name":"LatLng"}},{"title":"name","name":"convert"},{"title":"memberof","description":"LatLng"},{"title":"static"}],"context":{"loc":{"start":{"line":42,"column":0},"end":{"line":50,"column":2}},"file":"/Users/tmcw/src/mapbox-gl-js/js/geo/lat_lng.js","code":"'use strict';\n\nmodule.exports = LatLng;\n\nvar wrap = require('../util/util').wrap;\n\n/**\n * Create a latitude, longitude object from a given latitude and longitude pair in degrees.\n *\n * @class LatLng\n * @classdesc A representation of a latitude and longitude point, in degrees.\n * @param {number} lat latitude\n * @param {number} lng longitude\n * @example\n * var latlng = new mapboxgl.LatLng(37.76, -122.44);\n *\n */\nfunction LatLng(lat, lng) {\n    if (isNaN(lat) || isNaN(lng)) {\n        throw new Error('Invalid LatLng object: (' + lat + ', ' + lng + ')');\n    }\n    this.lat = +lat;\n    this.lng = +lng;\n}\n\n/**\n * Return a new `LatLng` object whose longitude is wrapped to the range (-180, 180).\n *\n * @returns {LatLng} wrapped LatLng object\n */\nLatLng.prototype.wrap = function () {\n    return new LatLng(this.lat, wrap(this.lng, -180, 180));\n};\n\n/**\n * Convert an array to a `LatLng` object, or return an existing `LatLng` object\n * unchanged.\n *\n * @param {Array<number>|LatLng} input `input` to convert\n * @returns {LatLng} LatLng object or original input\n */\nLatLng.convert = function (input) {\n    if (input instanceof LatLng) {\n        return input;\n    }\n    if (Array.isArray(input)) {\n        return new LatLng(input[0], input[1]);\n    }\n    return input;\n};","path":"js/geo/lat_lng.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/geo/lat_lng.js#L42-L50"},"params":[{"title":"param","description":"`input` to convert","type":{"type":"UnionType","elements":[{"type":"TypeApplication","expression":{"type":"NameExpression","name":"Array"},"applications":[{"type":"NameExpression","name":"number"}]},{"type":"NameExpression","name":"LatLng"}]},"name":"input"}],"returns":[{"title":"returns","description":"LatLng object or original input","type":{"type":"NameExpression","name":"LatLng"}}],"name":"convert","memberof":"LatLng","scope":"static","members":{"instance":[],"static":[]},"path":["LatLng","convert"]}]},"path":["LatLng"]},{"description":"Methods mixed in to other classes for event capabilities.","tags":[{"title":"mixin","description":null,"name":"Evented"},{"title":"name","name":"Evented"},{"title":"kind","kind":"mixin"}],"context":{"loc":{"start":{"line":9,"column":0},"end":{"line":100,"column":2}},"file":"/Users/tmcw/src/mapbox-gl-js/js/util/evented.js","code":"'use strict';\n\nvar util = require('./util');\n\n/**\n * Methods mixed in to other classes for event capabilities.\n * @mixin Evented\n */\nvar Evented = {\n\n    /**\n     * Subscribe to a specified event with a listener function the latter gets the data object that was passed to `fire` and additionally `target` and `type` properties\n     *\n     * @param {String} type Event type\n     * @param {Function} listener Function to be called when the event is fired\n     */\n    on: function(type, fn) {\n        this._events = this._events || {};\n        this._events[type] = this._events[type] || [];\n        this._events[type].push(fn);\n\n        return this;\n    },\n\n    /**\n     * Remove a event listener\n     *\n     * @param {String} [type] Event type. If none is specified, remove all listeners\n     * @param {Function} [listener] Function to be called when the event is fired. If none is specified all listeners are removed\n     */\n    off: function(type, fn) {\n        if (!type) {\n            // clear all listeners if no arguments specified\n            delete this._events;\n            return this;\n        }\n\n        if (!this.listens(type)) return this;\n\n        if (fn) {\n            var idx = this._events[type].indexOf(fn);\n            if (idx >= 0) {\n                this._events[type].splice(idx, 1);\n            }\n            if (!this._events[type].length) {\n                delete this._events[type];\n            }\n        } else {\n            delete this._events[type];\n        }\n\n        return this;\n    },\n\n    /**\n     * Call a function once when an event has fired\n     *\n     * @param {String} type Event type.\n     * @param {Function} listener Function to be called once when the event is fired\n     */\n    once: function(type, fn) {\n        var wrapper = function(data) {\n            this.off(type, wrapper);\n            fn.call(this, data);\n        }.bind(this);\n        this.on(type, wrapper);\n        return this;\n    },\n\n    /**\n     * Fire event of a given string type with the given data object\n     *\n     * @param {String} type The event name\n     * @param {Object} [data] Optional data passed down to the event object\n     * @returns {Boolean} Returns true if the object listens to an event of a particular type\n     */\n    fire: function(type, data) {\n        if (!this.listens(type)) return this;\n\n        data = util.extend({}, data);\n        util.extend(data, {type: type, target: this});\n\n        // make sure adding/removing listeners inside other listeners won't cause infinite loop\n        var listeners = this._events[type].slice();\n\n        for (var i = 0; i < listeners.length; i++) {\n            listeners[i].call(this, data);\n        }\n\n        return this;\n    },\n\n    /**\n     * Check if an event is registered to a type\n     * @returns {Boolean} Returns true if the object listens to an event of a particular type\n     */\n    listens: function(type) {\n        return !!(this._events && this._events[type]);\n    }\n};\n\nmodule.exports = Evented;","path":"js/util/evented.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/util/evented.js#L9-L100"},"name":"Evented","kind":"mixin","members":{"instance":[],"static":[{"description":"Check if an event is registered to a type","tags":[{"title":"returns","description":"Returns true if the object listens to an event of a particular type","type":{"type":"NameExpression","name":"Boolean"}},{"title":"name","name":"listens"},{"title":"memberof","description":"Evented"},{"title":"static"}],"context":{"loc":{"start":{"line":97,"column":4},"end":{"line":99,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/util/evented.js","code":"{\n\n    /**\n     * Subscribe to a specified event with a listener function the latter gets the data object that was passed to `fire` and additionally `target` and `type` properties\n     *\n     * @param {String} type Event type\n     * @param {Function} listener Function to be called when the event is fired\n     */\n    on: function(type, fn) {\n        this._events = this._events || {};\n        this._events[type] = this._events[type] || [];\n        this._events[type].push(fn);\n\n        return this;\n    },\n\n    /**\n     * Remove a event listener\n     *\n     * @param {String} [type] Event type. If none is specified, remove all listeners\n     * @param {Function} [listener] Function to be called when the event is fired. If none is specified all listeners are removed\n     */\n    off: function(type, fn) {\n        if (!type) {\n            // clear all listeners if no arguments specified\n            delete this._events;\n            return this;\n        }\n\n        if (!this.listens(type)) return this;\n\n        if (fn) {\n            var idx = this._events[type].indexOf(fn);\n            if (idx >= 0) {\n                this._events[type].splice(idx, 1);\n            }\n            if (!this._events[type].length) {\n                delete this._events[type];\n            }\n        } else {\n            delete this._events[type];\n        }\n\n        return this;\n    },\n\n    /**\n     * Call a function once when an event has fired\n     *\n     * @param {String} type Event type.\n     * @param {Function} listener Function to be called once when the event is fired\n     */\n    once: function(type, fn) {\n        var wrapper = function(data) {\n            this.off(type, wrapper);\n            fn.call(this, data);\n        }.bind(this);\n        this.on(type, wrapper);\n        return this;\n    },\n\n    /**\n     * Fire event of a given string type with the given data object\n     *\n     * @param {String} type The event name\n     * @param {Object} [data] Optional data passed down to the event object\n     * @returns {Boolean} Returns true if the object listens to an event of a particular type\n     */\n    fire: function(type, data) {\n        if (!this.listens(type)) return this;\n\n        data = util.extend({}, data);\n        util.extend(data, {type: type, target: this});\n\n        // make sure adding/removing listeners inside other listeners won't cause infinite loop\n        var listeners = this._events[type].slice();\n\n        for (var i = 0; i < listeners.length; i++) {\n            listeners[i].call(this, data);\n        }\n\n        return this;\n    },\n\n    /**\n     * Check if an event is registered to a type\n     * @returns {Boolean} Returns true if the object listens to an event of a particular type\n     */\n    listens: function(type) {\n        return !!(this._events && this._events[type]);\n    }\n}","path":"js/util/evented.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/util/evented.js#L97-L99"},"returns":[{"title":"returns","description":"Returns true if the object listens to an event of a particular type","type":{"type":"NameExpression","name":"Boolean"}}],"name":"listens","memberof":"Evented","scope":"static","members":{"instance":[],"static":[]},"path":["Evented","listens"]},{"description":"Call a function once when an event has fired","tags":[{"title":"param","description":"Event type.","type":{"type":"NameExpression","name":"String"},"name":"type"},{"title":"param","description":"Function to be called once when the event is fired","type":{"type":"NameExpression","name":"Function"},"name":"listener"},{"title":"name","name":"once"},{"title":"memberof","description":"Evented"},{"title":"static"}],"context":{"loc":{"start":{"line":61,"column":4},"end":{"line":68,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/util/evented.js","code":"{\n\n    /**\n     * Subscribe to a specified event with a listener function the latter gets the data object that was passed to `fire` and additionally `target` and `type` properties\n     *\n     * @param {String} type Event type\n     * @param {Function} listener Function to be called when the event is fired\n     */\n    on: function(type, fn) {\n        this._events = this._events || {};\n        this._events[type] = this._events[type] || [];\n        this._events[type].push(fn);\n\n        return this;\n    },\n\n    /**\n     * Remove a event listener\n     *\n     * @param {String} [type] Event type. If none is specified, remove all listeners\n     * @param {Function} [listener] Function to be called when the event is fired. If none is specified all listeners are removed\n     */\n    off: function(type, fn) {\n        if (!type) {\n            // clear all listeners if no arguments specified\n            delete this._events;\n            return this;\n        }\n\n        if (!this.listens(type)) return this;\n\n        if (fn) {\n            var idx = this._events[type].indexOf(fn);\n            if (idx >= 0) {\n                this._events[type].splice(idx, 1);\n            }\n            if (!this._events[type].length) {\n                delete this._events[type];\n            }\n        } else {\n            delete this._events[type];\n        }\n\n        return this;\n    },\n\n    /**\n     * Call a function once when an event has fired\n     *\n     * @param {String} type Event type.\n     * @param {Function} listener Function to be called once when the event is fired\n     */\n    once: function(type, fn) {\n        var wrapper = function(data) {\n            this.off(type, wrapper);\n            fn.call(this, data);\n        }.bind(this);\n        this.on(type, wrapper);\n        return this;\n    },\n\n    /**\n     * Fire event of a given string type with the given data object\n     *\n     * @param {String} type The event name\n     * @param {Object} [data] Optional data passed down to the event object\n     * @returns {Boolean} Returns true if the object listens to an event of a particular type\n     */\n    fire: function(type, data) {\n        if (!this.listens(type)) return this;\n\n        data = util.extend({}, data);\n        util.extend(data, {type: type, target: this});\n\n        // make sure adding/removing listeners inside other listeners won't cause infinite loop\n        var listeners = this._events[type].slice();\n\n        for (var i = 0; i < listeners.length; i++) {\n            listeners[i].call(this, data);\n        }\n\n        return this;\n    },\n\n    /**\n     * Check if an event is registered to a type\n     * @returns {Boolean} Returns true if the object listens to an event of a particular type\n     */\n    listens: function(type) {\n        return !!(this._events && this._events[type]);\n    }\n}","path":"js/util/evented.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/util/evented.js#L61-L68"},"params":[{"title":"param","description":"Event type.","type":{"type":"NameExpression","name":"String"},"name":"type"},{"title":"param","description":"Function to be called once when the event is fired","type":{"type":"NameExpression","name":"Function"},"name":"listener"}],"name":"once","memberof":"Evented","scope":"static","members":{"instance":[],"static":[]},"path":["Evented","once"]},{"description":"Remove a event listener","tags":[{"title":"name","name":"off"},{"title":"memberof","description":"Evented"},{"title":"static"}],"context":{"loc":{"start":{"line":31,"column":4},"end":{"line":53,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/util/evented.js","code":"{\n\n    /**\n     * Subscribe to a specified event with a listener function the latter gets the data object that was passed to `fire` and additionally `target` and `type` properties\n     *\n     * @param {String} type Event type\n     * @param {Function} listener Function to be called when the event is fired\n     */\n    on: function(type, fn) {\n        this._events = this._events || {};\n        this._events[type] = this._events[type] || [];\n        this._events[type].push(fn);\n\n        return this;\n    },\n\n    /**\n     * Remove a event listener\n     *\n     * @param {String} [type] Event type. If none is specified, remove all listeners\n     * @param {Function} [listener] Function to be called when the event is fired. If none is specified all listeners are removed\n     */\n    off: function(type, fn) {\n        if (!type) {\n            // clear all listeners if no arguments specified\n            delete this._events;\n            return this;\n        }\n\n        if (!this.listens(type)) return this;\n\n        if (fn) {\n            var idx = this._events[type].indexOf(fn);\n            if (idx >= 0) {\n                this._events[type].splice(idx, 1);\n            }\n            if (!this._events[type].length) {\n                delete this._events[type];\n            }\n        } else {\n            delete this._events[type];\n        }\n\n        return this;\n    },\n\n    /**\n     * Call a function once when an event has fired\n     *\n     * @param {String} type Event type.\n     * @param {Function} listener Function to be called once when the event is fired\n     */\n    once: function(type, fn) {\n        var wrapper = function(data) {\n            this.off(type, wrapper);\n            fn.call(this, data);\n        }.bind(this);\n        this.on(type, wrapper);\n        return this;\n    },\n\n    /**\n     * Fire event of a given string type with the given data object\n     *\n     * @param {String} type The event name\n     * @param {Object} [data] Optional data passed down to the event object\n     * @returns {Boolean} Returns true if the object listens to an event of a particular type\n     */\n    fire: function(type, data) {\n        if (!this.listens(type)) return this;\n\n        data = util.extend({}, data);\n        util.extend(data, {type: type, target: this});\n\n        // make sure adding/removing listeners inside other listeners won't cause infinite loop\n        var listeners = this._events[type].slice();\n\n        for (var i = 0; i < listeners.length; i++) {\n            listeners[i].call(this, data);\n        }\n\n        return this;\n    },\n\n    /**\n     * Check if an event is registered to a type\n     * @returns {Boolean} Returns true if the object listens to an event of a particular type\n     */\n    listens: function(type) {\n        return !!(this._events && this._events[type]);\n    }\n}","path":"js/util/evented.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/util/evented.js#L31-L53"},"name":"off","memberof":"Evented","scope":"static","members":{"instance":[],"static":[]},"path":["Evented","off"]},{"description":"Subscribe to a specified event with a listener function the latter gets the data object that was passed to `fire` and additionally `target` and `type` properties","tags":[{"title":"param","description":"Event type","type":{"type":"NameExpression","name":"String"},"name":"type"},{"title":"param","description":"Function to be called when the event is fired","type":{"type":"NameExpression","name":"Function"},"name":"listener"},{"title":"name","name":"on"},{"title":"memberof","description":"Evented"},{"title":"static"}],"context":{"loc":{"start":{"line":17,"column":4},"end":{"line":23,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/util/evented.js","code":"{\n\n    /**\n     * Subscribe to a specified event with a listener function the latter gets the data object that was passed to `fire` and additionally `target` and `type` properties\n     *\n     * @param {String} type Event type\n     * @param {Function} listener Function to be called when the event is fired\n     */\n    on: function(type, fn) {\n        this._events = this._events || {};\n        this._events[type] = this._events[type] || [];\n        this._events[type].push(fn);\n\n        return this;\n    },\n\n    /**\n     * Remove a event listener\n     *\n     * @param {String} [type] Event type. If none is specified, remove all listeners\n     * @param {Function} [listener] Function to be called when the event is fired. If none is specified all listeners are removed\n     */\n    off: function(type, fn) {\n        if (!type) {\n            // clear all listeners if no arguments specified\n            delete this._events;\n            return this;\n        }\n\n        if (!this.listens(type)) return this;\n\n        if (fn) {\n            var idx = this._events[type].indexOf(fn);\n            if (idx >= 0) {\n                this._events[type].splice(idx, 1);\n            }\n            if (!this._events[type].length) {\n                delete this._events[type];\n            }\n        } else {\n            delete this._events[type];\n        }\n\n        return this;\n    },\n\n    /**\n     * Call a function once when an event has fired\n     *\n     * @param {String} type Event type.\n     * @param {Function} listener Function to be called once when the event is fired\n     */\n    once: function(type, fn) {\n        var wrapper = function(data) {\n            this.off(type, wrapper);\n            fn.call(this, data);\n        }.bind(this);\n        this.on(type, wrapper);\n        return this;\n    },\n\n    /**\n     * Fire event of a given string type with the given data object\n     *\n     * @param {String} type The event name\n     * @param {Object} [data] Optional data passed down to the event object\n     * @returns {Boolean} Returns true if the object listens to an event of a particular type\n     */\n    fire: function(type, data) {\n        if (!this.listens(type)) return this;\n\n        data = util.extend({}, data);\n        util.extend(data, {type: type, target: this});\n\n        // make sure adding/removing listeners inside other listeners won't cause infinite loop\n        var listeners = this._events[type].slice();\n\n        for (var i = 0; i < listeners.length; i++) {\n            listeners[i].call(this, data);\n        }\n\n        return this;\n    },\n\n    /**\n     * Check if an event is registered to a type\n     * @returns {Boolean} Returns true if the object listens to an event of a particular type\n     */\n    listens: function(type) {\n        return !!(this._events && this._events[type]);\n    }\n}","path":"js/util/evented.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/util/evented.js#L17-L23"},"params":[{"title":"param","description":"Event type","type":{"type":"NameExpression","name":"String"},"name":"type"},{"title":"param","description":"Function to be called when the event is fired","type":{"type":"NameExpression","name":"Function"},"name":"listener"}],"name":"on","memberof":"Evented","scope":"static","members":{"instance":[],"static":[]},"path":["Evented","on"]},{"description":"Fire event of a given string type with the given data object","tags":[{"title":"param","description":"The event name","type":{"type":"NameExpression","name":"String"},"name":"type"},{"title":"name","name":"fire"},{"title":"memberof","description":"Evented"},{"title":"static"}],"context":{"loc":{"start":{"line":77,"column":4},"end":{"line":91,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/util/evented.js","code":"{\n\n    /**\n     * Subscribe to a specified event with a listener function the latter gets the data object that was passed to `fire` and additionally `target` and `type` properties\n     *\n     * @param {String} type Event type\n     * @param {Function} listener Function to be called when the event is fired\n     */\n    on: function(type, fn) {\n        this._events = this._events || {};\n        this._events[type] = this._events[type] || [];\n        this._events[type].push(fn);\n\n        return this;\n    },\n\n    /**\n     * Remove a event listener\n     *\n     * @param {String} [type] Event type. If none is specified, remove all listeners\n     * @param {Function} [listener] Function to be called when the event is fired. If none is specified all listeners are removed\n     */\n    off: function(type, fn) {\n        if (!type) {\n            // clear all listeners if no arguments specified\n            delete this._events;\n            return this;\n        }\n\n        if (!this.listens(type)) return this;\n\n        if (fn) {\n            var idx = this._events[type].indexOf(fn);\n            if (idx >= 0) {\n                this._events[type].splice(idx, 1);\n            }\n            if (!this._events[type].length) {\n                delete this._events[type];\n            }\n        } else {\n            delete this._events[type];\n        }\n\n        return this;\n    },\n\n    /**\n     * Call a function once when an event has fired\n     *\n     * @param {String} type Event type.\n     * @param {Function} listener Function to be called once when the event is fired\n     */\n    once: function(type, fn) {\n        var wrapper = function(data) {\n            this.off(type, wrapper);\n            fn.call(this, data);\n        }.bind(this);\n        this.on(type, wrapper);\n        return this;\n    },\n\n    /**\n     * Fire event of a given string type with the given data object\n     *\n     * @param {String} type The event name\n     * @param {Object} [data] Optional data passed down to the event object\n     * @returns {Boolean} Returns true if the object listens to an event of a particular type\n     */\n    fire: function(type, data) {\n        if (!this.listens(type)) return this;\n\n        data = util.extend({}, data);\n        util.extend(data, {type: type, target: this});\n\n        // make sure adding/removing listeners inside other listeners won't cause infinite loop\n        var listeners = this._events[type].slice();\n\n        for (var i = 0; i < listeners.length; i++) {\n            listeners[i].call(this, data);\n        }\n\n        return this;\n    },\n\n    /**\n     * Check if an event is registered to a type\n     * @returns {Boolean} Returns true if the object listens to an event of a particular type\n     */\n    listens: function(type) {\n        return !!(this._events && this._events[type]);\n    }\n}","path":"js/util/evented.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/util/evented.js#L77-L91"},"params":[{"title":"param","description":"The event name","type":{"type":"NameExpression","name":"String"},"name":"type"}],"name":"fire","memberof":"Evented","scope":"static","members":{"instance":[],"static":[]},"path":["Evented","fire"]}]},"path":["Evented"]},{"description":"Creates a bounding box from the given pair of points. If parameteres are omitted, a `null` bounding box is created.","tags":[{"title":"class","description":null,"type":null,"name":"LatLngBounds"},{"title":"classdesc","description":"A representation of rectangular box on the earth, defined by its southwest and northeast points in latitude and longitude."},{"title":"param","description":"southwest","type":{"type":"NameExpression","name":"LatLng"},"name":"sw"},{"title":"param","description":"northeast","type":{"type":"NameExpression","name":"LatLng"},"name":"ne"},{"title":"example","description":"var sw = new mapboxgl.LatLng(0, 0);\nvar ne = new mapboxgl.LatLng(10, -10);\nvar bounds = new mapboxgl.LatLngBounds(sw, ne);"},{"title":"name","name":"LatLngBounds"},{"title":"kind","kind":"class"}],"context":{"loc":{"start":{"line":20,"column":0},"end":{"line":28,"column":1}},"file":"/Users/tmcw/src/mapbox-gl-js/js/geo/lat_lng_bounds.js","code":"'use strict';\n\nmodule.exports = LatLngBounds;\n\nvar LatLng = require('./lat_lng');\n\n/**\n * Creates a bounding box from the given pair of points. If parameteres are omitted, a `null` bounding box is created.\n *\n * @class LatLngBounds\n * @classdesc A representation of rectangular box on the earth, defined by its southwest and northeast points in latitude and longitude.\n * @param {LatLng} sw southwest\n * @param {LatLng} ne northeast\n * @example\n * var sw = new mapboxgl.LatLng(0, 0);\n * var ne = new mapboxgl.LatLng(10, -10);\n * var bounds = new mapboxgl.LatLngBounds(sw, ne);\n *\n */\nfunction LatLngBounds(sw, ne) {\n    if (!sw) return;\n\n    var latlngs = ne ? [sw, ne] : sw;\n\n    for (var i = 0, len = latlngs.length; i < len; i++) {\n        this.extend(latlngs[i]);\n    }\n}\n\nLatLngBounds.prototype = {\n\n    /**\n     * Extend the bounds to include a given LatLng or LatLngBounds.\n     *\n     * @param {LatLng|LatLngBounds} obj object to extend to\n     * @returns {LatLngBounds} `this`\n     */\n    extend: function(obj) {\n        var sw = this._sw,\n            ne = this._ne,\n            sw2, ne2;\n\n        if (obj instanceof LatLng) {\n            sw2 = obj;\n            ne2 = obj;\n\n        } else if (obj instanceof LatLngBounds) {\n            sw2 = obj._sw;\n            ne2 = obj._ne;\n\n            if (!sw2 || !ne2) return this;\n\n        } else {\n            return obj ? this.extend(LatLng.convert(obj) || LatLngBounds.convert(obj)) : this;\n        }\n\n        if (!sw && !ne) {\n            this._sw = new LatLng(sw2.lat, sw2.lng);\n            this._ne = new LatLng(ne2.lat, ne2.lng);\n\n        } else {\n            sw.lat = Math.min(sw2.lat, sw.lat);\n            sw.lng = Math.min(sw2.lng, sw.lng);\n            ne.lat = Math.max(ne2.lat, ne.lat);\n            ne.lng = Math.max(ne2.lng, ne.lng);\n        }\n\n        return this;\n    },\n\n    /**\n     * Get the point equidistant from this box's corners\n     * @returns {LatLng} centerpoint\n     */\n    getCenter: function() {\n        return new LatLng((this._sw.lat + this._ne.lat) / 2, (this._sw.lng + this._ne.lng) / 2);\n    },\n\n    /**\n     * Get southwest corner\n     * @returns {LatLng} southwest\n     */\n    getSouthWest: function() { return this._sw; },\n\n    /**\n     * Get northeast corner\n     * @returns {LatLng} northeast\n     */\n    getNorthEast: function() { return this._ne; },\n\n    /**\n     * Get northwest corner\n     * @returns {LatLng} northwest\n     */\n    getNorthWest: function() { return new LatLng(this.getNorth(), this.getWest()); },\n\n    /**\n     * Get southeast corner\n     * @returns {LatLng} southeast\n     */\n    getSouthEast: function() { return new LatLng(this.getSouth(), this.getEast()); },\n\n    /**\n     * Get west edge longitude\n     * @returns {number} west\n     */\n    getWest:  function() { return this._sw.lng; },\n\n    /**\n     * Get south edge latitude\n     * @returns {number} south\n     */\n    getSouth: function() { return this._sw.lat; },\n\n    /**\n     * Get east edge longitude\n     * @returns {number} east\n     */\n    getEast:  function() { return this._ne.lng; },\n\n    /**\n     * Get north edge latitude\n     * @returns {number} north\n     */\n    getNorth: function() { return this._ne.lat; }\n};\n\n// constructs LatLngBounds from an array if necessary\nLatLngBounds.convert = function (a) {\n    if (!a || a instanceof LatLngBounds) return a;\n    return new LatLngBounds(a);\n};","path":"js/geo/lat_lng_bounds.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/geo/lat_lng_bounds.js#L20-L28"},"classdesc":"A representation of rectangular box on the earth, defined by its southwest and northeast points in latitude and longitude.","params":[{"title":"param","description":"southwest","type":{"type":"NameExpression","name":"LatLng"},"name":"sw"},{"title":"param","description":"northeast","type":{"type":"NameExpression","name":"LatLng"},"name":"ne"}],"examples":["<span class=\"hljs-keyword\">var</span> sw = <span class=\"hljs-keyword\">new</span> mapboxgl.LatLng(<span class=\"hljs-number\">0</span>, <span class=\"hljs-number\">0</span>);\n<span class=\"hljs-keyword\">var</span> ne = <span class=\"hljs-keyword\">new</span> mapboxgl.LatLng(<span class=\"hljs-number\">10</span>, -<span class=\"hljs-number\">10</span>);\n<span class=\"hljs-keyword\">var</span> bounds = <span class=\"hljs-keyword\">new</span> mapboxgl.LatLngBounds(sw, ne);"],"name":"LatLngBounds","kind":"class","members":{"instance":[{"description":"Get southwest corner","tags":[{"title":"returns","description":"southwest","type":{"type":"NameExpression","name":"LatLng"}},{"title":"name","name":"getSouthWest"},{"title":"memberof","description":"LatLngBounds"},{"title":"instance"}],"context":{"loc":{"start":{"line":83,"column":4},"end":{"line":83,"column":49}},"file":"/Users/tmcw/src/mapbox-gl-js/js/geo/lat_lng_bounds.js","code":"{\n\n    /**\n     * Extend the bounds to include a given LatLng or LatLngBounds.\n     *\n     * @param {LatLng|LatLngBounds} obj object to extend to\n     * @returns {LatLngBounds} `this`\n     */\n    extend: function(obj) {\n        var sw = this._sw,\n            ne = this._ne,\n            sw2, ne2;\n\n        if (obj instanceof LatLng) {\n            sw2 = obj;\n            ne2 = obj;\n\n        } else if (obj instanceof LatLngBounds) {\n            sw2 = obj._sw;\n            ne2 = obj._ne;\n\n            if (!sw2 || !ne2) return this;\n\n        } else {\n            return obj ? this.extend(LatLng.convert(obj) || LatLngBounds.convert(obj)) : this;\n        }\n\n        if (!sw && !ne) {\n            this._sw = new LatLng(sw2.lat, sw2.lng);\n            this._ne = new LatLng(ne2.lat, ne2.lng);\n\n        } else {\n            sw.lat = Math.min(sw2.lat, sw.lat);\n            sw.lng = Math.min(sw2.lng, sw.lng);\n            ne.lat = Math.max(ne2.lat, ne.lat);\n            ne.lng = Math.max(ne2.lng, ne.lng);\n        }\n\n        return this;\n    },\n\n    /**\n     * Get the point equidistant from this box's corners\n     * @returns {LatLng} centerpoint\n     */\n    getCenter: function() {\n        return new LatLng((this._sw.lat + this._ne.lat) / 2, (this._sw.lng + this._ne.lng) / 2);\n    },\n\n    /**\n     * Get southwest corner\n     * @returns {LatLng} southwest\n     */\n    getSouthWest: function() { return this._sw; },\n\n    /**\n     * Get northeast corner\n     * @returns {LatLng} northeast\n     */\n    getNorthEast: function() { return this._ne; },\n\n    /**\n     * Get northwest corner\n     * @returns {LatLng} northwest\n     */\n    getNorthWest: function() { return new LatLng(this.getNorth(), this.getWest()); },\n\n    /**\n     * Get southeast corner\n     * @returns {LatLng} southeast\n     */\n    getSouthEast: function() { return new LatLng(this.getSouth(), this.getEast()); },\n\n    /**\n     * Get west edge longitude\n     * @returns {number} west\n     */\n    getWest:  function() { return this._sw.lng; },\n\n    /**\n     * Get south edge latitude\n     * @returns {number} south\n     */\n    getSouth: function() { return this._sw.lat; },\n\n    /**\n     * Get east edge longitude\n     * @returns {number} east\n     */\n    getEast:  function() { return this._ne.lng; },\n\n    /**\n     * Get north edge latitude\n     * @returns {number} north\n     */\n    getNorth: function() { return this._ne.lat; }\n}","path":"js/geo/lat_lng_bounds.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/geo/lat_lng_bounds.js#L83-L83"},"returns":[{"title":"returns","description":"southwest","type":{"type":"NameExpression","name":"LatLng"}}],"name":"getSouthWest","memberof":"LatLngBounds","scope":"instance","members":{"instance":[],"static":[]},"path":["LatLngBounds","getSouthWest"]},{"description":"Get south edge latitude","tags":[{"title":"returns","description":"south","type":{"type":"NameExpression","name":"number"}},{"title":"name","name":"getSouth"},{"title":"memberof","description":"LatLngBounds"},{"title":"instance"}],"context":{"loc":{"start":{"line":113,"column":4},"end":{"line":113,"column":49}},"file":"/Users/tmcw/src/mapbox-gl-js/js/geo/lat_lng_bounds.js","code":"{\n\n    /**\n     * Extend the bounds to include a given LatLng or LatLngBounds.\n     *\n     * @param {LatLng|LatLngBounds} obj object to extend to\n     * @returns {LatLngBounds} `this`\n     */\n    extend: function(obj) {\n        var sw = this._sw,\n            ne = this._ne,\n            sw2, ne2;\n\n        if (obj instanceof LatLng) {\n            sw2 = obj;\n            ne2 = obj;\n\n        } else if (obj instanceof LatLngBounds) {\n            sw2 = obj._sw;\n            ne2 = obj._ne;\n\n            if (!sw2 || !ne2) return this;\n\n        } else {\n            return obj ? this.extend(LatLng.convert(obj) || LatLngBounds.convert(obj)) : this;\n        }\n\n        if (!sw && !ne) {\n            this._sw = new LatLng(sw2.lat, sw2.lng);\n            this._ne = new LatLng(ne2.lat, ne2.lng);\n\n        } else {\n            sw.lat = Math.min(sw2.lat, sw.lat);\n            sw.lng = Math.min(sw2.lng, sw.lng);\n            ne.lat = Math.max(ne2.lat, ne.lat);\n            ne.lng = Math.max(ne2.lng, ne.lng);\n        }\n\n        return this;\n    },\n\n    /**\n     * Get the point equidistant from this box's corners\n     * @returns {LatLng} centerpoint\n     */\n    getCenter: function() {\n        return new LatLng((this._sw.lat + this._ne.lat) / 2, (this._sw.lng + this._ne.lng) / 2);\n    },\n\n    /**\n     * Get southwest corner\n     * @returns {LatLng} southwest\n     */\n    getSouthWest: function() { return this._sw; },\n\n    /**\n     * Get northeast corner\n     * @returns {LatLng} northeast\n     */\n    getNorthEast: function() { return this._ne; },\n\n    /**\n     * Get northwest corner\n     * @returns {LatLng} northwest\n     */\n    getNorthWest: function() { return new LatLng(this.getNorth(), this.getWest()); },\n\n    /**\n     * Get southeast corner\n     * @returns {LatLng} southeast\n     */\n    getSouthEast: function() { return new LatLng(this.getSouth(), this.getEast()); },\n\n    /**\n     * Get west edge longitude\n     * @returns {number} west\n     */\n    getWest:  function() { return this._sw.lng; },\n\n    /**\n     * Get south edge latitude\n     * @returns {number} south\n     */\n    getSouth: function() { return this._sw.lat; },\n\n    /**\n     * Get east edge longitude\n     * @returns {number} east\n     */\n    getEast:  function() { return this._ne.lng; },\n\n    /**\n     * Get north edge latitude\n     * @returns {number} north\n     */\n    getNorth: function() { return this._ne.lat; }\n}","path":"js/geo/lat_lng_bounds.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/geo/lat_lng_bounds.js#L113-L113"},"returns":[{"title":"returns","description":"south","type":{"type":"NameExpression","name":"number"}}],"name":"getSouth","memberof":"LatLngBounds","scope":"instance","members":{"instance":[],"static":[]},"path":["LatLngBounds","getSouth"]},{"description":"Get northeast corner","tags":[{"title":"returns","description":"northeast","type":{"type":"NameExpression","name":"LatLng"}},{"title":"name","name":"getNorthEast"},{"title":"memberof","description":"LatLngBounds"},{"title":"instance"}],"context":{"loc":{"start":{"line":89,"column":4},"end":{"line":89,"column":49}},"file":"/Users/tmcw/src/mapbox-gl-js/js/geo/lat_lng_bounds.js","code":"{\n\n    /**\n     * Extend the bounds to include a given LatLng or LatLngBounds.\n     *\n     * @param {LatLng|LatLngBounds} obj object to extend to\n     * @returns {LatLngBounds} `this`\n     */\n    extend: function(obj) {\n        var sw = this._sw,\n            ne = this._ne,\n            sw2, ne2;\n\n        if (obj instanceof LatLng) {\n            sw2 = obj;\n            ne2 = obj;\n\n        } else if (obj instanceof LatLngBounds) {\n            sw2 = obj._sw;\n            ne2 = obj._ne;\n\n            if (!sw2 || !ne2) return this;\n\n        } else {\n            return obj ? this.extend(LatLng.convert(obj) || LatLngBounds.convert(obj)) : this;\n        }\n\n        if (!sw && !ne) {\n            this._sw = new LatLng(sw2.lat, sw2.lng);\n            this._ne = new LatLng(ne2.lat, ne2.lng);\n\n        } else {\n            sw.lat = Math.min(sw2.lat, sw.lat);\n            sw.lng = Math.min(sw2.lng, sw.lng);\n            ne.lat = Math.max(ne2.lat, ne.lat);\n            ne.lng = Math.max(ne2.lng, ne.lng);\n        }\n\n        return this;\n    },\n\n    /**\n     * Get the point equidistant from this box's corners\n     * @returns {LatLng} centerpoint\n     */\n    getCenter: function() {\n        return new LatLng((this._sw.lat + this._ne.lat) / 2, (this._sw.lng + this._ne.lng) / 2);\n    },\n\n    /**\n     * Get southwest corner\n     * @returns {LatLng} southwest\n     */\n    getSouthWest: function() { return this._sw; },\n\n    /**\n     * Get northeast corner\n     * @returns {LatLng} northeast\n     */\n    getNorthEast: function() { return this._ne; },\n\n    /**\n     * Get northwest corner\n     * @returns {LatLng} northwest\n     */\n    getNorthWest: function() { return new LatLng(this.getNorth(), this.getWest()); },\n\n    /**\n     * Get southeast corner\n     * @returns {LatLng} southeast\n     */\n    getSouthEast: function() { return new LatLng(this.getSouth(), this.getEast()); },\n\n    /**\n     * Get west edge longitude\n     * @returns {number} west\n     */\n    getWest:  function() { return this._sw.lng; },\n\n    /**\n     * Get south edge latitude\n     * @returns {number} south\n     */\n    getSouth: function() { return this._sw.lat; },\n\n    /**\n     * Get east edge longitude\n     * @returns {number} east\n     */\n    getEast:  function() { return this._ne.lng; },\n\n    /**\n     * Get north edge latitude\n     * @returns {number} north\n     */\n    getNorth: function() { return this._ne.lat; }\n}","path":"js/geo/lat_lng_bounds.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/geo/lat_lng_bounds.js#L89-L89"},"returns":[{"title":"returns","description":"northeast","type":{"type":"NameExpression","name":"LatLng"}}],"name":"getNorthEast","memberof":"LatLngBounds","scope":"instance","members":{"instance":[],"static":[]},"path":["LatLngBounds","getNorthEast"]},{"description":"Get northwest corner","tags":[{"title":"returns","description":"northwest","type":{"type":"NameExpression","name":"LatLng"}},{"title":"name","name":"getNorthWest"},{"title":"memberof","description":"LatLngBounds"},{"title":"instance"}],"context":{"loc":{"start":{"line":95,"column":4},"end":{"line":95,"column":84}},"file":"/Users/tmcw/src/mapbox-gl-js/js/geo/lat_lng_bounds.js","code":"{\n\n    /**\n     * Extend the bounds to include a given LatLng or LatLngBounds.\n     *\n     * @param {LatLng|LatLngBounds} obj object to extend to\n     * @returns {LatLngBounds} `this`\n     */\n    extend: function(obj) {\n        var sw = this._sw,\n            ne = this._ne,\n            sw2, ne2;\n\n        if (obj instanceof LatLng) {\n            sw2 = obj;\n            ne2 = obj;\n\n        } else if (obj instanceof LatLngBounds) {\n            sw2 = obj._sw;\n            ne2 = obj._ne;\n\n            if (!sw2 || !ne2) return this;\n\n        } else {\n            return obj ? this.extend(LatLng.convert(obj) || LatLngBounds.convert(obj)) : this;\n        }\n\n        if (!sw && !ne) {\n            this._sw = new LatLng(sw2.lat, sw2.lng);\n            this._ne = new LatLng(ne2.lat, ne2.lng);\n\n        } else {\n            sw.lat = Math.min(sw2.lat, sw.lat);\n            sw.lng = Math.min(sw2.lng, sw.lng);\n            ne.lat = Math.max(ne2.lat, ne.lat);\n            ne.lng = Math.max(ne2.lng, ne.lng);\n        }\n\n        return this;\n    },\n\n    /**\n     * Get the point equidistant from this box's corners\n     * @returns {LatLng} centerpoint\n     */\n    getCenter: function() {\n        return new LatLng((this._sw.lat + this._ne.lat) / 2, (this._sw.lng + this._ne.lng) / 2);\n    },\n\n    /**\n     * Get southwest corner\n     * @returns {LatLng} southwest\n     */\n    getSouthWest: function() { return this._sw; },\n\n    /**\n     * Get northeast corner\n     * @returns {LatLng} northeast\n     */\n    getNorthEast: function() { return this._ne; },\n\n    /**\n     * Get northwest corner\n     * @returns {LatLng} northwest\n     */\n    getNorthWest: function() { return new LatLng(this.getNorth(), this.getWest()); },\n\n    /**\n     * Get southeast corner\n     * @returns {LatLng} southeast\n     */\n    getSouthEast: function() { return new LatLng(this.getSouth(), this.getEast()); },\n\n    /**\n     * Get west edge longitude\n     * @returns {number} west\n     */\n    getWest:  function() { return this._sw.lng; },\n\n    /**\n     * Get south edge latitude\n     * @returns {number} south\n     */\n    getSouth: function() { return this._sw.lat; },\n\n    /**\n     * Get east edge longitude\n     * @returns {number} east\n     */\n    getEast:  function() { return this._ne.lng; },\n\n    /**\n     * Get north edge latitude\n     * @returns {number} north\n     */\n    getNorth: function() { return this._ne.lat; }\n}","path":"js/geo/lat_lng_bounds.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/geo/lat_lng_bounds.js#L95-L95"},"returns":[{"title":"returns","description":"northwest","type":{"type":"NameExpression","name":"LatLng"}}],"name":"getNorthWest","memberof":"LatLngBounds","scope":"instance","members":{"instance":[],"static":[]},"path":["LatLngBounds","getNorthWest"]},{"description":"Get southeast corner","tags":[{"title":"returns","description":"southeast","type":{"type":"NameExpression","name":"LatLng"}},{"title":"name","name":"getSouthEast"},{"title":"memberof","description":"LatLngBounds"},{"title":"instance"}],"context":{"loc":{"start":{"line":101,"column":4},"end":{"line":101,"column":84}},"file":"/Users/tmcw/src/mapbox-gl-js/js/geo/lat_lng_bounds.js","code":"{\n\n    /**\n     * Extend the bounds to include a given LatLng or LatLngBounds.\n     *\n     * @param {LatLng|LatLngBounds} obj object to extend to\n     * @returns {LatLngBounds} `this`\n     */\n    extend: function(obj) {\n        var sw = this._sw,\n            ne = this._ne,\n            sw2, ne2;\n\n        if (obj instanceof LatLng) {\n            sw2 = obj;\n            ne2 = obj;\n\n        } else if (obj instanceof LatLngBounds) {\n            sw2 = obj._sw;\n            ne2 = obj._ne;\n\n            if (!sw2 || !ne2) return this;\n\n        } else {\n            return obj ? this.extend(LatLng.convert(obj) || LatLngBounds.convert(obj)) : this;\n        }\n\n        if (!sw && !ne) {\n            this._sw = new LatLng(sw2.lat, sw2.lng);\n            this._ne = new LatLng(ne2.lat, ne2.lng);\n\n        } else {\n            sw.lat = Math.min(sw2.lat, sw.lat);\n            sw.lng = Math.min(sw2.lng, sw.lng);\n            ne.lat = Math.max(ne2.lat, ne.lat);\n            ne.lng = Math.max(ne2.lng, ne.lng);\n        }\n\n        return this;\n    },\n\n    /**\n     * Get the point equidistant from this box's corners\n     * @returns {LatLng} centerpoint\n     */\n    getCenter: function() {\n        return new LatLng((this._sw.lat + this._ne.lat) / 2, (this._sw.lng + this._ne.lng) / 2);\n    },\n\n    /**\n     * Get southwest corner\n     * @returns {LatLng} southwest\n     */\n    getSouthWest: function() { return this._sw; },\n\n    /**\n     * Get northeast corner\n     * @returns {LatLng} northeast\n     */\n    getNorthEast: function() { return this._ne; },\n\n    /**\n     * Get northwest corner\n     * @returns {LatLng} northwest\n     */\n    getNorthWest: function() { return new LatLng(this.getNorth(), this.getWest()); },\n\n    /**\n     * Get southeast corner\n     * @returns {LatLng} southeast\n     */\n    getSouthEast: function() { return new LatLng(this.getSouth(), this.getEast()); },\n\n    /**\n     * Get west edge longitude\n     * @returns {number} west\n     */\n    getWest:  function() { return this._sw.lng; },\n\n    /**\n     * Get south edge latitude\n     * @returns {number} south\n     */\n    getSouth: function() { return this._sw.lat; },\n\n    /**\n     * Get east edge longitude\n     * @returns {number} east\n     */\n    getEast:  function() { return this._ne.lng; },\n\n    /**\n     * Get north edge latitude\n     * @returns {number} north\n     */\n    getNorth: function() { return this._ne.lat; }\n}","path":"js/geo/lat_lng_bounds.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/geo/lat_lng_bounds.js#L101-L101"},"returns":[{"title":"returns","description":"southeast","type":{"type":"NameExpression","name":"LatLng"}}],"name":"getSouthEast","memberof":"LatLngBounds","scope":"instance","members":{"instance":[],"static":[]},"path":["LatLngBounds","getSouthEast"]},{"description":"Get west edge longitude","tags":[{"title":"returns","description":"west","type":{"type":"NameExpression","name":"number"}},{"title":"name","name":"getWest"},{"title":"memberof","description":"LatLngBounds"},{"title":"instance"}],"context":{"loc":{"start":{"line":107,"column":4},"end":{"line":107,"column":49}},"file":"/Users/tmcw/src/mapbox-gl-js/js/geo/lat_lng_bounds.js","code":"{\n\n    /**\n     * Extend the bounds to include a given LatLng or LatLngBounds.\n     *\n     * @param {LatLng|LatLngBounds} obj object to extend to\n     * @returns {LatLngBounds} `this`\n     */\n    extend: function(obj) {\n        var sw = this._sw,\n            ne = this._ne,\n            sw2, ne2;\n\n        if (obj instanceof LatLng) {\n            sw2 = obj;\n            ne2 = obj;\n\n        } else if (obj instanceof LatLngBounds) {\n            sw2 = obj._sw;\n            ne2 = obj._ne;\n\n            if (!sw2 || !ne2) return this;\n\n        } else {\n            return obj ? this.extend(LatLng.convert(obj) || LatLngBounds.convert(obj)) : this;\n        }\n\n        if (!sw && !ne) {\n            this._sw = new LatLng(sw2.lat, sw2.lng);\n            this._ne = new LatLng(ne2.lat, ne2.lng);\n\n        } else {\n            sw.lat = Math.min(sw2.lat, sw.lat);\n            sw.lng = Math.min(sw2.lng, sw.lng);\n            ne.lat = Math.max(ne2.lat, ne.lat);\n            ne.lng = Math.max(ne2.lng, ne.lng);\n        }\n\n        return this;\n    },\n\n    /**\n     * Get the point equidistant from this box's corners\n     * @returns {LatLng} centerpoint\n     */\n    getCenter: function() {\n        return new LatLng((this._sw.lat + this._ne.lat) / 2, (this._sw.lng + this._ne.lng) / 2);\n    },\n\n    /**\n     * Get southwest corner\n     * @returns {LatLng} southwest\n     */\n    getSouthWest: function() { return this._sw; },\n\n    /**\n     * Get northeast corner\n     * @returns {LatLng} northeast\n     */\n    getNorthEast: function() { return this._ne; },\n\n    /**\n     * Get northwest corner\n     * @returns {LatLng} northwest\n     */\n    getNorthWest: function() { return new LatLng(this.getNorth(), this.getWest()); },\n\n    /**\n     * Get southeast corner\n     * @returns {LatLng} southeast\n     */\n    getSouthEast: function() { return new LatLng(this.getSouth(), this.getEast()); },\n\n    /**\n     * Get west edge longitude\n     * @returns {number} west\n     */\n    getWest:  function() { return this._sw.lng; },\n\n    /**\n     * Get south edge latitude\n     * @returns {number} south\n     */\n    getSouth: function() { return this._sw.lat; },\n\n    /**\n     * Get east edge longitude\n     * @returns {number} east\n     */\n    getEast:  function() { return this._ne.lng; },\n\n    /**\n     * Get north edge latitude\n     * @returns {number} north\n     */\n    getNorth: function() { return this._ne.lat; }\n}","path":"js/geo/lat_lng_bounds.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/geo/lat_lng_bounds.js#L107-L107"},"returns":[{"title":"returns","description":"west","type":{"type":"NameExpression","name":"number"}}],"name":"getWest","memberof":"LatLngBounds","scope":"instance","members":{"instance":[],"static":[]},"path":["LatLngBounds","getWest"]},{"description":"Extend the bounds to include a given LatLng or LatLngBounds.","tags":[{"title":"param","description":"object to extend to","type":{"type":"UnionType","elements":[{"type":"NameExpression","name":"LatLng"},{"type":"NameExpression","name":"LatLngBounds"}]},"name":"obj"},{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"LatLngBounds"}},{"title":"name","name":"extend"},{"title":"memberof","description":"LatLngBounds"},{"title":"instance"}],"context":{"loc":{"start":{"line":38,"column":4},"end":{"line":69,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/geo/lat_lng_bounds.js","code":"{\n\n    /**\n     * Extend the bounds to include a given LatLng or LatLngBounds.\n     *\n     * @param {LatLng|LatLngBounds} obj object to extend to\n     * @returns {LatLngBounds} `this`\n     */\n    extend: function(obj) {\n        var sw = this._sw,\n            ne = this._ne,\n            sw2, ne2;\n\n        if (obj instanceof LatLng) {\n            sw2 = obj;\n            ne2 = obj;\n\n        } else if (obj instanceof LatLngBounds) {\n            sw2 = obj._sw;\n            ne2 = obj._ne;\n\n            if (!sw2 || !ne2) return this;\n\n        } else {\n            return obj ? this.extend(LatLng.convert(obj) || LatLngBounds.convert(obj)) : this;\n        }\n\n        if (!sw && !ne) {\n            this._sw = new LatLng(sw2.lat, sw2.lng);\n            this._ne = new LatLng(ne2.lat, ne2.lng);\n\n        } else {\n            sw.lat = Math.min(sw2.lat, sw.lat);\n            sw.lng = Math.min(sw2.lng, sw.lng);\n            ne.lat = Math.max(ne2.lat, ne.lat);\n            ne.lng = Math.max(ne2.lng, ne.lng);\n        }\n\n        return this;\n    },\n\n    /**\n     * Get the point equidistant from this box's corners\n     * @returns {LatLng} centerpoint\n     */\n    getCenter: function() {\n        return new LatLng((this._sw.lat + this._ne.lat) / 2, (this._sw.lng + this._ne.lng) / 2);\n    },\n\n    /**\n     * Get southwest corner\n     * @returns {LatLng} southwest\n     */\n    getSouthWest: function() { return this._sw; },\n\n    /**\n     * Get northeast corner\n     * @returns {LatLng} northeast\n     */\n    getNorthEast: function() { return this._ne; },\n\n    /**\n     * Get northwest corner\n     * @returns {LatLng} northwest\n     */\n    getNorthWest: function() { return new LatLng(this.getNorth(), this.getWest()); },\n\n    /**\n     * Get southeast corner\n     * @returns {LatLng} southeast\n     */\n    getSouthEast: function() { return new LatLng(this.getSouth(), this.getEast()); },\n\n    /**\n     * Get west edge longitude\n     * @returns {number} west\n     */\n    getWest:  function() { return this._sw.lng; },\n\n    /**\n     * Get south edge latitude\n     * @returns {number} south\n     */\n    getSouth: function() { return this._sw.lat; },\n\n    /**\n     * Get east edge longitude\n     * @returns {number} east\n     */\n    getEast:  function() { return this._ne.lng; },\n\n    /**\n     * Get north edge latitude\n     * @returns {number} north\n     */\n    getNorth: function() { return this._ne.lat; }\n}","path":"js/geo/lat_lng_bounds.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/geo/lat_lng_bounds.js#L38-L69"},"params":[{"title":"param","description":"object to extend to","type":{"type":"UnionType","elements":[{"type":"NameExpression","name":"LatLng"},{"type":"NameExpression","name":"LatLngBounds"}]},"name":"obj"}],"returns":[{"title":"returns","description":"`this`","type":{"type":"NameExpression","name":"LatLngBounds"}}],"name":"extend","memberof":"LatLngBounds","scope":"instance","members":{"instance":[],"static":[]},"path":["LatLngBounds","extend"]},{"description":"Get the point equidistant from this box's corners","tags":[{"title":"returns","description":"centerpoint","type":{"type":"NameExpression","name":"LatLng"}},{"title":"name","name":"getCenter"},{"title":"memberof","description":"LatLngBounds"},{"title":"instance"}],"context":{"loc":{"start":{"line":75,"column":4},"end":{"line":77,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/geo/lat_lng_bounds.js","code":"{\n\n    /**\n     * Extend the bounds to include a given LatLng or LatLngBounds.\n     *\n     * @param {LatLng|LatLngBounds} obj object to extend to\n     * @returns {LatLngBounds} `this`\n     */\n    extend: function(obj) {\n        var sw = this._sw,\n            ne = this._ne,\n            sw2, ne2;\n\n        if (obj instanceof LatLng) {\n            sw2 = obj;\n            ne2 = obj;\n\n        } else if (obj instanceof LatLngBounds) {\n            sw2 = obj._sw;\n            ne2 = obj._ne;\n\n            if (!sw2 || !ne2) return this;\n\n        } else {\n            return obj ? this.extend(LatLng.convert(obj) || LatLngBounds.convert(obj)) : this;\n        }\n\n        if (!sw && !ne) {\n            this._sw = new LatLng(sw2.lat, sw2.lng);\n            this._ne = new LatLng(ne2.lat, ne2.lng);\n\n        } else {\n            sw.lat = Math.min(sw2.lat, sw.lat);\n            sw.lng = Math.min(sw2.lng, sw.lng);\n            ne.lat = Math.max(ne2.lat, ne.lat);\n            ne.lng = Math.max(ne2.lng, ne.lng);\n        }\n\n        return this;\n    },\n\n    /**\n     * Get the point equidistant from this box's corners\n     * @returns {LatLng} centerpoint\n     */\n    getCenter: function() {\n        return new LatLng((this._sw.lat + this._ne.lat) / 2, (this._sw.lng + this._ne.lng) / 2);\n    },\n\n    /**\n     * Get southwest corner\n     * @returns {LatLng} southwest\n     */\n    getSouthWest: function() { return this._sw; },\n\n    /**\n     * Get northeast corner\n     * @returns {LatLng} northeast\n     */\n    getNorthEast: function() { return this._ne; },\n\n    /**\n     * Get northwest corner\n     * @returns {LatLng} northwest\n     */\n    getNorthWest: function() { return new LatLng(this.getNorth(), this.getWest()); },\n\n    /**\n     * Get southeast corner\n     * @returns {LatLng} southeast\n     */\n    getSouthEast: function() { return new LatLng(this.getSouth(), this.getEast()); },\n\n    /**\n     * Get west edge longitude\n     * @returns {number} west\n     */\n    getWest:  function() { return this._sw.lng; },\n\n    /**\n     * Get south edge latitude\n     * @returns {number} south\n     */\n    getSouth: function() { return this._sw.lat; },\n\n    /**\n     * Get east edge longitude\n     * @returns {number} east\n     */\n    getEast:  function() { return this._ne.lng; },\n\n    /**\n     * Get north edge latitude\n     * @returns {number} north\n     */\n    getNorth: function() { return this._ne.lat; }\n}","path":"js/geo/lat_lng_bounds.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/geo/lat_lng_bounds.js#L75-L77"},"returns":[{"title":"returns","description":"centerpoint","type":{"type":"NameExpression","name":"LatLng"}}],"name":"getCenter","memberof":"LatLngBounds","scope":"instance","members":{"instance":[],"static":[]},"path":["LatLngBounds","getCenter"]},{"description":"Get east edge longitude","tags":[{"title":"returns","description":"east","type":{"type":"NameExpression","name":"number"}},{"title":"name","name":"getEast"},{"title":"memberof","description":"LatLngBounds"},{"title":"instance"}],"context":{"loc":{"start":{"line":119,"column":4},"end":{"line":119,"column":49}},"file":"/Users/tmcw/src/mapbox-gl-js/js/geo/lat_lng_bounds.js","code":"{\n\n    /**\n     * Extend the bounds to include a given LatLng or LatLngBounds.\n     *\n     * @param {LatLng|LatLngBounds} obj object to extend to\n     * @returns {LatLngBounds} `this`\n     */\n    extend: function(obj) {\n        var sw = this._sw,\n            ne = this._ne,\n            sw2, ne2;\n\n        if (obj instanceof LatLng) {\n            sw2 = obj;\n            ne2 = obj;\n\n        } else if (obj instanceof LatLngBounds) {\n            sw2 = obj._sw;\n            ne2 = obj._ne;\n\n            if (!sw2 || !ne2) return this;\n\n        } else {\n            return obj ? this.extend(LatLng.convert(obj) || LatLngBounds.convert(obj)) : this;\n        }\n\n        if (!sw && !ne) {\n            this._sw = new LatLng(sw2.lat, sw2.lng);\n            this._ne = new LatLng(ne2.lat, ne2.lng);\n\n        } else {\n            sw.lat = Math.min(sw2.lat, sw.lat);\n            sw.lng = Math.min(sw2.lng, sw.lng);\n            ne.lat = Math.max(ne2.lat, ne.lat);\n            ne.lng = Math.max(ne2.lng, ne.lng);\n        }\n\n        return this;\n    },\n\n    /**\n     * Get the point equidistant from this box's corners\n     * @returns {LatLng} centerpoint\n     */\n    getCenter: function() {\n        return new LatLng((this._sw.lat + this._ne.lat) / 2, (this._sw.lng + this._ne.lng) / 2);\n    },\n\n    /**\n     * Get southwest corner\n     * @returns {LatLng} southwest\n     */\n    getSouthWest: function() { return this._sw; },\n\n    /**\n     * Get northeast corner\n     * @returns {LatLng} northeast\n     */\n    getNorthEast: function() { return this._ne; },\n\n    /**\n     * Get northwest corner\n     * @returns {LatLng} northwest\n     */\n    getNorthWest: function() { return new LatLng(this.getNorth(), this.getWest()); },\n\n    /**\n     * Get southeast corner\n     * @returns {LatLng} southeast\n     */\n    getSouthEast: function() { return new LatLng(this.getSouth(), this.getEast()); },\n\n    /**\n     * Get west edge longitude\n     * @returns {number} west\n     */\n    getWest:  function() { return this._sw.lng; },\n\n    /**\n     * Get south edge latitude\n     * @returns {number} south\n     */\n    getSouth: function() { return this._sw.lat; },\n\n    /**\n     * Get east edge longitude\n     * @returns {number} east\n     */\n    getEast:  function() { return this._ne.lng; },\n\n    /**\n     * Get north edge latitude\n     * @returns {number} north\n     */\n    getNorth: function() { return this._ne.lat; }\n}","path":"js/geo/lat_lng_bounds.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/geo/lat_lng_bounds.js#L119-L119"},"returns":[{"title":"returns","description":"east","type":{"type":"NameExpression","name":"number"}}],"name":"getEast","memberof":"LatLngBounds","scope":"instance","members":{"instance":[],"static":[]},"path":["LatLngBounds","getEast"]},{"description":"Get north edge latitude","tags":[{"title":"returns","description":"north","type":{"type":"NameExpression","name":"number"}},{"title":"name","name":"getNorth"},{"title":"memberof","description":"LatLngBounds"},{"title":"instance"}],"context":{"loc":{"start":{"line":125,"column":4},"end":{"line":125,"column":49}},"file":"/Users/tmcw/src/mapbox-gl-js/js/geo/lat_lng_bounds.js","code":"{\n\n    /**\n     * Extend the bounds to include a given LatLng or LatLngBounds.\n     *\n     * @param {LatLng|LatLngBounds} obj object to extend to\n     * @returns {LatLngBounds} `this`\n     */\n    extend: function(obj) {\n        var sw = this._sw,\n            ne = this._ne,\n            sw2, ne2;\n\n        if (obj instanceof LatLng) {\n            sw2 = obj;\n            ne2 = obj;\n\n        } else if (obj instanceof LatLngBounds) {\n            sw2 = obj._sw;\n            ne2 = obj._ne;\n\n            if (!sw2 || !ne2) return this;\n\n        } else {\n            return obj ? this.extend(LatLng.convert(obj) || LatLngBounds.convert(obj)) : this;\n        }\n\n        if (!sw && !ne) {\n            this._sw = new LatLng(sw2.lat, sw2.lng);\n            this._ne = new LatLng(ne2.lat, ne2.lng);\n\n        } else {\n            sw.lat = Math.min(sw2.lat, sw.lat);\n            sw.lng = Math.min(sw2.lng, sw.lng);\n            ne.lat = Math.max(ne2.lat, ne.lat);\n            ne.lng = Math.max(ne2.lng, ne.lng);\n        }\n\n        return this;\n    },\n\n    /**\n     * Get the point equidistant from this box's corners\n     * @returns {LatLng} centerpoint\n     */\n    getCenter: function() {\n        return new LatLng((this._sw.lat + this._ne.lat) / 2, (this._sw.lng + this._ne.lng) / 2);\n    },\n\n    /**\n     * Get southwest corner\n     * @returns {LatLng} southwest\n     */\n    getSouthWest: function() { return this._sw; },\n\n    /**\n     * Get northeast corner\n     * @returns {LatLng} northeast\n     */\n    getNorthEast: function() { return this._ne; },\n\n    /**\n     * Get northwest corner\n     * @returns {LatLng} northwest\n     */\n    getNorthWest: function() { return new LatLng(this.getNorth(), this.getWest()); },\n\n    /**\n     * Get southeast corner\n     * @returns {LatLng} southeast\n     */\n    getSouthEast: function() { return new LatLng(this.getSouth(), this.getEast()); },\n\n    /**\n     * Get west edge longitude\n     * @returns {number} west\n     */\n    getWest:  function() { return this._sw.lng; },\n\n    /**\n     * Get south edge latitude\n     * @returns {number} south\n     */\n    getSouth: function() { return this._sw.lat; },\n\n    /**\n     * Get east edge longitude\n     * @returns {number} east\n     */\n    getEast:  function() { return this._ne.lng; },\n\n    /**\n     * Get north edge latitude\n     * @returns {number} north\n     */\n    getNorth: function() { return this._ne.lat; }\n}","path":"js/geo/lat_lng_bounds.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/geo/lat_lng_bounds.js#L125-L125"},"returns":[{"title":"returns","description":"north","type":{"type":"NameExpression","name":"number"}}],"name":"getNorth","memberof":"LatLngBounds","scope":"instance","members":{"instance":[],"static":[]},"path":["LatLngBounds","getNorth"]}],"static":[]},"path":["LatLngBounds"]},{"description":"Create a Video data source instance given an options object","tags":[{"title":"class","description":null,"type":null,"name":"VideoSource"},{"title":"name","name":"VideoSource"},{"title":"kind","kind":"class"}],"context":{"loc":{"start":{"line":35,"column":0},"end":{"line":66,"column":1}},"file":"/Users/tmcw/src/mapbox-gl-js/js/source/video_source.js","code":"'use strict';\n\nvar util = require('../util/util');\nvar Tile = require('./tile');\nvar TileCoord = require('./tile_coord');\nvar LatLng = require('../geo/lat_lng');\nvar Point = require('point-geometry');\nvar Evented = require('../util/evented');\nvar ajax = require('../util/ajax');\n\nmodule.exports = VideoSource;\n\n/**\n * Create a Video data source instance given an options object\n * @class VideoSource\n * @param {Object} [options]\n * @param {String|Array} options.url A string or array of URL(s) to video files\n * @param {Array} options.coordinates lat,lng coordinates in order clockwise starting at the top left: tl, tr, br, bl\n * @example\n * var sourceObj = new mapboxgl.VideoSource({\n *    url: [\n *        'https://www.mapbox.com/videos/baltimore-smoke.mp4',\n *        'https://www.mapbox.com/videos/baltimore-smoke.webm'\n *    ],\n *    coordinates: [\n *        [39.18579907229748, -76.54335737228394],\n *        [39.1838364847587, -76.52803659439087],\n *        [39.17683392507606, -76.5295386314392],\n *        [39.17876344106642, -76.54520273208618]\n *    ]\n * });\n * map.addSource('some id', sourceObj); // add\n * map.removeSource('some id');  // remove\n */\nfunction VideoSource(options) {\n    this.coordinates = options.coordinates;\n\n    ajax.getVideo(options.url, function(err, video) {\n        // @TODO handle errors via event.\n        if (err) return;\n\n        this.video = video;\n        this.video.loop = true;\n\n        var loopID;\n\n        // start repainting when video starts playing\n        this.video.addEventListener('playing', function() {\n            loopID = this.map.style.animationLoop.set(Infinity);\n            this.map._rerender();\n        }.bind(this));\n\n        // stop repainting when video stops\n        this.video.addEventListener('pause', function() {\n            this.map.style.animationLoop.cancel(loopID);\n        }.bind(this));\n\n        this._loaded = true;\n\n        if (this.map) {\n            this.video.play();\n            this.createTile();\n            this.fire('change');\n        }\n    }.bind(this));\n}\n\nVideoSource.prototype = util.inherit(Evented, {\n    onAdd: function(map) {\n        this.map = map;\n        if (this.video) {\n            this.video.play();\n            this.createTile();\n        }\n    },\n\n    createTile: function() {\n        /*\n         * Calculate which mercator tile is suitable for rendering the video in\n         * and create a buffer with the corner coordinates. These coordinates\n         * may be outside the tile, because raster tiles aren't clipped when rendering.\n         */\n        var map = this.map;\n        var coords = this.coordinates.map(function(latlng) {\n            var loc = LatLng.convert(latlng);\n            return TileCoord.zoomTo(map.transform.locationCoordinate(loc), 0);\n        });\n\n        var minX = Infinity;\n        var minY = Infinity;\n        var maxX = -Infinity;\n        var maxY = -Infinity;\n\n        for (var i = 0; i < coords.length; i++) {\n            minX = Math.min(minX, coords[i].column);\n            minY = Math.min(minY, coords[i].row);\n            maxX = Math.max(maxX, coords[i].column);\n            maxY = Math.max(maxY, coords[i].row);\n        }\n\n        var dx = maxX - minX;\n        var dy = maxY - minY;\n        var dMax = Math.max(dx, dy);\n        var center = TileCoord.zoomTo({\n            column: (minX + maxX) / 2,\n            row: (minY + maxY) / 2,\n            zoom: 0\n        }, Math.floor(-Math.log(dMax) / Math.LN2));\n\n        var tileExtent = 4096;\n        var tileCoords = coords.map(function(coord) {\n            var zoomedCoord = TileCoord.zoomTo(coord, center.zoom);\n            return new Point(\n                Math.round((zoomedCoord.column - center.column) * tileExtent),\n                Math.round((zoomedCoord.row - center.row) * tileExtent));\n        });\n\n        var gl = map.painter.gl;\n        var maxInt16 = 32767;\n        var array = new Int16Array([\n            tileCoords[0].x, tileCoords[0].y, 0, 0,\n            tileCoords[1].x, tileCoords[1].y, maxInt16, 0,\n            tileCoords[3].x, tileCoords[3].y, 0, maxInt16,\n            tileCoords[2].x, tileCoords[2].y, maxInt16, maxInt16\n        ]);\n\n        this.tile = new Tile();\n        this.tile.buckets = {};\n\n        this.tile.boundsBuffer = gl.createBuffer();\n        gl.bindBuffer(gl.ARRAY_BUFFER, this.tile.boundsBuffer);\n        gl.bufferData(gl.ARRAY_BUFFER, array, gl.STATIC_DRAW);\n\n        this.center = center;\n    },\n\n    loaded: function() {\n        return this.video && this.video.readyState >= 2;\n    },\n\n    update: function() {\n        // noop\n    },\n\n    render: function(layers, painter) {\n        if (!this._loaded) return;\n        if (this.video.readyState < 2) return; // not enough data for current position\n\n        var c = this.center;\n        this.tile.calculateMatrices(c.zoom, c.column, c.row, this.map.transform, painter);\n\n        var gl = painter.gl;\n        if (!this.tile.texture) {\n            this.tile.texture = gl.createTexture();\n            gl.bindTexture(gl.TEXTURE_2D, this.tile.texture);\n            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.video);\n        } else {\n            gl.bindTexture(gl.TEXTURE_2D, this.tile.texture);\n            gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, this.video);\n        }\n\n        painter.drawLayers(layers, this.tile.posMatrix, this.tile);\n    },\n\n    featuresAt: function(point, params, callback) {\n        return callback(null, []);\n    }\n});","path":"js/source/video_source.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/source/video_source.js#L35-L66"},"name":"VideoSource","kind":"class","members":{"instance":[],"static":[]},"path":["VideoSource"]},{"description":"","tags":[{"title":"typedef","description":"[animOptions]","type":{"type":"NameExpression","name":"Object"}},{"title":"name","name":"extend"},{"title":"kind","kind":"typedef"}],"context":{"loc":{"start":{"line":17,"column":0},"end":{"line":494,"column":3}},"file":"/Users/tmcw/src/mapbox-gl-js/js/ui/easings.js","code":"'use strict';\n\nvar util = require('../util/util');\nvar interpolate = require('../util/interpolate');\nvar browser = require('../util/browser');\nvar LatLng = require('../geo/lat_lng');\nvar LatLngBounds = require('../geo/lat_lng_bounds');\nvar Point = require('point-geometry');\n\n/**\n * @typedef {Object} [animOptions]\n * @param {Number} [animOptions.duration=500] Number in milliseconds\n * @param {Function} animOptions.easing\n * @param {Array} [animOptions.offset=[0,0]] point, origin of movement relative to map center\n * @param {Boolean} [animOptions.animate=true] When set to false, no animation happens\n */\nutil.extend(exports, /** @lends Map.prototype */{\n    isEasing: function() {\n        return !!this._abortFn;\n    },\n\n    /**\n     * Stop current animation\n     *\n     * @returns {this}\n     */\n    stop: function() {\n        if (this._abortFn) {\n            this._abortFn.call(this);\n            delete this._abortFn;\n\n            this._finishFn.call(this);\n            delete this._finishFn;\n        }\n        return this;\n    },\n\n    _ease: function(frame, finish, options) {\n        this._finishFn = finish;\n        this._abortFn = browser.timed(function (t) {\n            frame.call(this, options.easing(t));\n            if (t === 1) {\n                delete this._abortFn;\n                this._finishFn.call(this);\n                delete this._finishFn;\n            }\n        }, options.animate === false ? 0 : options.duration, this);\n    },\n\n    /**\n     * Pan by a certain number of pixels\n     *\n     * @param {Array} offset [x, y]\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    panBy: function(offset, options) {\n        this.panTo(this.transform.center, util.extend({offset: Point.convert(offset).mult(-1)}, options));\n        return this;\n    },\n\n    /**\n     * Pan to a certain location with easing\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    panTo: function(latlng, options) {\n        this.stop();\n\n        latlng = LatLng.convert(latlng);\n\n        options = util.extend({\n            duration: 500,\n            easing: util.ease,\n            offset: [0, 0]\n        }, options);\n\n        var tr = this.transform,\n            offset = Point.convert(options.offset).rotate(-tr.angle),\n            from = tr.point,\n            to = tr.project(latlng).sub(offset);\n\n        if (!options.noMoveStart) {\n            this.fire('movestart');\n        }\n\n        this._ease(function(k) {\n            tr.center = tr.unproject(from.add(to.sub(from).mult(k)));\n            this._move();\n        }, function() {\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Zooms to a certain zoom level with easing.\n     *\n     * @param {Number} zoom\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomTo: function(zoom, options) {\n        this.stop();\n\n        options = util.extend({\n            duration: 500\n        }, options);\n\n        options.easing = this._updateEasing(options.duration, zoom, options.easing);\n\n        var tr = this.transform,\n            around = tr.center,\n            startZoom = tr.zoom;\n\n        if (options.around) {\n            around = LatLng.convert(options.around);\n        } else if (options.offset) {\n            around = tr.pointLocation(tr.centerPoint.add(Point.convert(options.offset)));\n        }\n\n        if (options.animate === false) options.duration = 0;\n\n        if (!this.zooming) {\n            this.zooming = true;\n            this.fire('movestart');\n        }\n\n        this._ease(function(k) {\n            tr.setZoomAround(interpolate(startZoom, zoom, k), around);\n            this.animationLoop.set(300); // text fading\n            this._move(true);\n        }, function() {\n            this.ease = null;\n            if (options.duration >= 200) {\n                this.zooming = false;\n                this.fire('moveend');\n            }\n        }, options);\n\n        if (options.duration < 200) {\n            clearTimeout(this._onZoomEnd);\n            this._onZoomEnd = setTimeout(function() {\n                this.zooming = false;\n                this._rerender();\n                this.fire('moveend');\n            }.bind(this), 200);\n        }\n\n        return this;\n    },\n\n    /**\n     * Zoom in by 1 level\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomIn: function(options) {\n        this.zoomTo(this.getZoom() + 1, options);\n    },\n\n    /**\n     * Zoom out by 1 level\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    zoomOut: function(options) {\n        this.zoomTo(this.getZoom() - 1, options);\n    },\n\n    /**\n     * Rotate bearing by a certain number of degrees with easing\n     *\n     * @param {Number} bearing\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    rotateTo: function(bearing, options) {\n        this.stop();\n\n        options = util.extend({\n            duration: 500,\n            easing: util.ease\n        }, options);\n\n        var tr = this.transform,\n            start = this.getBearing(),\n            around = tr.center;\n\n        if (options.around) {\n            around = LatLng.convert(options.around);\n        } else if (options.offset) {\n            around = tr.pointLocation(tr.centerPoint.add(Point.convert(options.offset)));\n        }\n\n        bearing = this._normalizeBearing(bearing, start);\n\n        this.rotating = true;\n        this.fire('movestart');\n\n        this._ease(function(k) {\n            tr.setBearingAround(interpolate(start, bearing, k), around);\n            this._move(false, true);\n        }, function() {\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Sets map bearing to 0 (north) with easing\n     *\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    resetNorth: function(options) {\n        return this.rotateTo(0, util.extend({duration: 1000}, options));\n    },\n\n    /**\n     * Zoom to contain certain geographical bounds\n     *\n     * @param {Array} bounds [[minLat, minLng], [maxLat, maxLng]]\n     * @param {Object} options\n     * @param {Number} [options.speed=1.2] How fast animation occurs\n     * @param {Number} [options.curve=1.42] How much zooming out occurs during animation\n     * @param {Function} options.easing\n     * @param {Number} options.padding how much padding there is around the given bounds on each side in pixels\n     * @param {Number} options.maxZoom\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    fitBounds: function(bounds, options) {\n\n        options = util.extend({\n            padding: 0,\n            offset: [0, 0],\n            maxZoom: Infinity\n        }, options);\n\n        bounds = LatLngBounds.convert(bounds);\n\n        var offset = Point.convert(options.offset),\n            tr = this.transform,\n            nw = tr.project(bounds.getNorthWest()),\n            se = tr.project(bounds.getSouthEast()),\n            size = se.sub(nw),\n            center = tr.unproject(nw.add(se).div(2)),\n\n            scaleX = (tr.width - options.padding * 2 - Math.abs(offset.x) * 2) / size.x,\n            scaleY = (tr.height - options.padding * 2 - Math.abs(offset.y) * 2) / size.y,\n\n            zoom = Math.min(tr.scaleZoom(tr.scale * Math.min(scaleX, scaleY)), options.maxZoom);\n\n        return options.linear ?\n            this.easeTo(center, zoom, 0, options) :\n            this.flyTo(center, zoom, 0, options);\n    },\n\n    /**\n     * Easing animation to a specified location/zoom/bearing\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {Number} zoom\n     * @param {Number} bearing\n     * @param {Number} pitch\n     * @param {animOptions}\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    easeTo: function(latlng, zoom, bearing, pitch, options) {\n        this.stop();\n\n        options = util.extend({\n            offset: [0, 0],\n            duration: 500,\n            easing: util.ease\n        }, options);\n\n        var tr = this.transform,\n            offset = Point.convert(options.offset).rotate(-tr.angle),\n            startZoom = this.getZoom(),\n            startBearing = this.getBearing(),\n            startPitch = this.getPitch();\n\n        latlng = LatLng.convert(latlng);\n        zoom = zoom === undefined ? startZoom : zoom;\n        bearing = bearing === undefined ? startBearing : this._normalizeBearing(bearing, startBearing);\n        pitch = pitch === undefined ? startPitch : pitch;\n\n        var scale = tr.zoomScale(zoom - startZoom),\n            from = tr.point,\n            to = latlng ? tr.project(latlng).sub(offset.div(scale)) : tr.point,\n            around;\n\n        if (zoom !== startZoom) {\n            around = tr.pointLocation(tr.centerPoint.add(to.sub(from).div(1 - 1 / scale)));\n            this.zooming = true;\n        }\n        if (startBearing !== bearing) this.rotating = true;\n\n        this.fire('movestart');\n\n        this._ease(function (k) {\n            if (zoom !== startZoom) {\n                tr.setZoomAround(interpolate(startZoom, zoom, k), around);\n            } else {\n                tr.center = tr.unproject(from.add(to.sub(from).mult(k)));\n            }\n\n            if (bearing !== startBearing) {\n                tr.bearing = interpolate(startBearing, bearing, k);\n            }\n\n            if (pitch !== startPitch) {\n                tr.pitch = interpolate(startPitch, pitch, k);\n            }\n\n            this.animationLoop.set(300); // text fading\n            this._move(zoom !== startZoom, bearing !== startBearing);\n        }, function() {\n            this.zooming = false;\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    /**\n     * Flying animation to a specified location/zoom/bearing with automatic curve\n     *\n     * @param {Object} latlng a `LatLng` object\n     * @param {Number} zoom\n     * @param {Number} bearing\n     * @param {Object} options\n     * @param {Number} [options.speed=1.2] How fast animation occurs\n     * @param {Number} [options.curve=1.42] How much zooming out occurs during animation\n     * @param {Function} options.easing\n     * @fires movestart\n     * @fires moveend\n     * @returns {this}\n     */\n    flyTo: function(latlng, zoom, bearing, options) {\n        this.stop();\n\n        options = util.extend({\n            offset: [0, 0],\n            speed: 1.2,\n            curve: 1.42,\n            easing: util.ease\n        }, options);\n\n        latlng = LatLng.convert(latlng);\n\n        var offset = Point.convert(options.offset),\n            tr = this.transform,\n            startZoom = this.getZoom(),\n            startBearing = this.getBearing();\n\n        zoom = zoom === undefined ? startZoom : zoom;\n        bearing = bearing === undefined ? startBearing : this._normalizeBearing(bearing, startBearing);\n\n        var scale = tr.zoomScale(zoom - startZoom),\n            from = tr.point,\n            to = tr.project(latlng).sub(offset.div(scale));\n\n        if (options.animate === false) {\n            return this.setView(latlng, zoom, bearing, this.getPitch());\n        }\n\n        var startWorldSize = tr.worldSize,\n            rho = options.curve,\n            V = options.speed,\n\n            w0 = Math.max(tr.width, tr.height),\n            w1 = w0 / scale,\n            u1 = to.sub(from).mag(),\n            rho2 = rho * rho;\n\n        function r(i) {\n            var b = (w1 * w1 - w0 * w0 + (i ? -1 : 1) * rho2 * rho2 * u1 * u1) / (2 * (i ? w1 : w0) * rho2 * u1);\n            return Math.log(Math.sqrt(b * b + 1) - b);\n        }\n\n        function sinh(n) { return (Math.exp(n) - Math.exp(-n)) / 2; }\n        function cosh(n) { return (Math.exp(n) + Math.exp(-n)) / 2; }\n        function tanh(n) { return sinh(n) / cosh(n); }\n\n        var r0 = r(0),\n            w = function (s) { return (cosh(r0) / cosh(r0 + rho * s)); },\n            u = function (s) { return w0 * ((cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2) / u1; },\n            S = (r(1) - r0) / rho;\n\n        if (Math.abs(u1) < 0.000001) {\n            if (Math.abs(w0 - w1) < 0.000001) return this;\n\n            var k = w1 < w0 ? -1 : 1;\n            S = Math.abs(Math.log(w1 / w0)) / rho;\n\n            u = function() { return 0; };\n            w = function(s) { return Math.exp(k * rho * s); };\n        }\n\n        options.duration = 1000 * S / V;\n\n        this.zooming = true;\n        if (startBearing !== bearing) this.rotating = true;\n\n        this.fire('movestart');\n\n        this._ease(function (k) {\n            var s = k * S,\n                us = u(s);\n\n            tr.zoom = startZoom + tr.scaleZoom(1 / w(s));\n            tr.center = tr.unproject(from.add(to.sub(from).mult(us)), startWorldSize);\n\n            if (bearing !== startBearing) {\n                tr.bearing = interpolate(startBearing, bearing, k);\n            }\n\n            this.animationLoop.set(300); // text fading\n\n            this._move(true, bearing !== startBearing);\n        }, function() {\n            this.zooming = false;\n            this.rotating = false;\n            this.fire('moveend');\n        }, options);\n\n        return this;\n    },\n\n    // convert bearing so that it's numerically close to the current one so that it interpolates properly\n    _normalizeBearing: function(bearing, currentBearing) {\n        bearing = util.wrap(bearing, -180, 180);\n        var diff = Math.abs(bearing - currentBearing);\n        if (Math.abs(bearing - 360 - currentBearing) < diff) bearing -= 360;\n        if (Math.abs(bearing + 360 - currentBearing) < diff) bearing += 360;\n        return bearing;\n    },\n\n    _updateEasing: function(duration, zoom, bezier) {\n        var easing;\n\n        if (this.ease) {\n            var ease = this.ease,\n                t = (Date.now() - ease.start) / ease.duration,\n                speed = ease.easing(t + 0.01) - ease.easing(t),\n\n                // Quick hack to make new bezier that is continuous with last\n                x = 0.27 / Math.sqrt(speed * speed + 0.0001) * 0.01,\n                y = Math.sqrt(0.27 * 0.27 - x * x);\n\n            easing = util.bezier(x, y, 0.25, 1);\n        } else {\n            easing = bezier ? util.bezier.apply(util, bezier) : util.ease;\n        }\n\n        // store information on current easing\n        this.ease = {\n            start: (new Date()).getTime(),\n            to: Math.pow(2, zoom),\n            duration: duration,\n            easing: easing\n        };\n\n        return easing;\n    }\n});","path":"js/ui/easings.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/ui/easings.js#L17-L494"},"name":"extend","kind":"typedef","members":{"instance":[],"static":[]},"path":["extend"]},{"description":"latitude to absolute y coord","tags":[{"title":"param","description":null,"type":{"type":"NameExpression","name":"Number"},"name":"lat"},{"title":"name","name":"latY"},{"title":"memberof","description":"Transform"},{"title":"instance"}],"context":{"loc":{"start":{"line":131,"column":4},"end":{"line":134,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/geo/transform.js","code":"{\n    get minZoom() { return this._minZoom; },\n    set minZoom(zoom) {\n        this._minZoom = zoom;\n        this.zoom = Math.max(this.zoom, zoom);\n    },\n\n    get maxZoom() { return this._maxZoom; },\n    set maxZoom(zoom) {\n        this._maxZoom = zoom;\n        this.zoom = Math.min(this.zoom, zoom);\n    },\n\n    get worldSize() {\n        return this.tileSize * this.scale;\n    },\n\n    get centerPoint() {\n        return this.size._div(2);\n    },\n\n    get size() {\n        return new Point(this.width, this.height);\n    },\n\n    get bearing() {\n        return -this.angle / Math.PI * 180;\n    },\n    set bearing(bearing) {\n        this.angle = -wrap(bearing, -180, 180) * Math.PI / 180;\n    },\n\n    get pitch() {\n        return this._pitch / Math.PI * 180;\n    },\n    set pitch(pitch) {\n        this._pitch = Math.min(60, pitch) / 180 * Math.PI;\n    },\n\n    get altitude() {\n        return this._altitude;\n    },\n    set altitude(altitude) {\n        this._altitude = Math.max(0.75, altitude);\n    },\n\n    get zoom() { return this._zoom; },\n    set zoom(zoom) {\n        zoom = Math.min(Math.max(zoom, this.minZoom), this.maxZoom);\n        this._zoom = zoom;\n        this.scale = this.zoomScale(zoom);\n        this.tileZoom = Math.floor(zoom);\n        this.zoomFraction = zoom - this.tileZoom;\n        this._constrain();\n    },\n\n    zoomScale: function(zoom) { return Math.pow(2, zoom); },\n    scaleZoom: function(scale) { return Math.log(scale) / Math.LN2; },\n\n    project: function(latlng, worldSize) {\n        return new Point(\n            this.lngX(latlng.lng, worldSize),\n            this.latY(latlng.lat, worldSize));\n    },\n\n    unproject: function(point, worldSize) {\n        return new LatLng(\n            this.yLat(point.y, worldSize),\n            this.xLng(point.x, worldSize));\n    },\n\n    get x() { return this.lngX(this.center.lng); },\n    get y() { return this.latY(this.center.lat); },\n\n    get point() { return new Point(this.x, this.y); },\n\n    /**\n     * lat/lon <-> absolute pixel coords conversion\n     * @param {Number} lon\n     * @param {Number} [worldSize=this.worldSize]\n     * @returns {Number} pixel coordinate\n     * @private\n     */\n    lngX: function(lon, worldSize) {\n        return (180 + lon) * (worldSize || this.worldSize) / 360;\n    },\n    /**\n     * latitude to absolute y coord\n     *\n     * @param {Number} lat\n     * @param {Number} [worldSize=this.worldSize]\n     * @returns {Number} pixel coordinate\n     * @private\n     */\n    latY: function(lat, worldSize) {\n        var y = 180 / Math.PI * Math.log(Math.tan(Math.PI / 4 + lat * Math.PI / 360));\n        return (180 - y) * (worldSize || this.worldSize) / 360;\n    },\n\n    xLng: function(x, worldSize) {\n        return x * 360 / (worldSize || this.worldSize) - 180;\n    },\n    yLat: function(y, worldSize) {\n        var y2 = 180 - y * 360 / (worldSize || this.worldSize);\n        return 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90;\n    },\n\n    panBy: function(offset) {\n        var point = this.centerPoint._add(offset);\n        this.center = this.pointLocation(point);\n        this._constrain();\n    },\n\n    setLocationAtPoint: function(latlng, point) {\n        var c = this.locationCoordinate(latlng);\n        var coordAtPoint = this.pointCoordinate(point);\n        var coordCenter = this.pointCoordinate(this.centerPoint);\n\n        var translate = coordAtPoint._sub(c);\n        this.center = this.coordinateLocation(coordCenter._sub(translate));\n\n        this._constrain();\n    },\n\n    setZoomAround: function(zoom, center) {\n        var p = this.locationPoint(center);\n        this.zoom = zoom;\n        this.setLocationAtPoint(center, p);\n    },\n\n    setBearingAround: function(bearing, center) {\n        var p = this.locationPoint(center);\n        this.bearing = bearing;\n        this.setLocationAtPoint(center, p);\n    },\n\n    locationPoint: function(latlng) {\n        return this.coordinatePoint(this.locationCoordinate(latlng));\n    },\n\n    pointLocation: function(p) {\n        return this.coordinateLocation(this.pointCoordinate(p));\n    },\n\n    locationCoordinate: function(latlng) {\n        var k = this.zoomScale(this.tileZoom) / this.worldSize;\n        return new Coordinate(\n            this.lngX(latlng.lng) * k,\n            this.latY(latlng.lat) * k,\n            this.tileZoom);\n    },\n\n    coordinateLocation: function(coord) {\n        var worldSize = this.zoomScale(coord.zoom);\n        return new LatLng(\n            this.yLat(coord.row, worldSize),\n            this.xLng(coord.column, worldSize));\n    },\n\n    pointCoordinate: function(p, targetZ) {\n\n        if (targetZ === undefined) targetZ = 0;\n\n        var matrix = this.coordinatePointMatrix(this.tileZoom);\n        var inverted = mat4.invert(new Float64Array(16), matrix);\n\n        if (!inverted) throw \"failed to invert matrix\";\n\n        // since we don't know the correct projected z value for the point,\n        // unproject two points to get a line and then find the point on that\n        // line with z=0\n\n        var coord0 = vec4.transformMat4([], [p.x, p.y, 0, 1], inverted);\n        var coord1 = vec4.transformMat4([], [p.x, p.y, 1, 1], inverted);\n\n        var w0 = coord0[3];\n        var w1 = coord1[3];\n        var x0 = coord0[0] / w0;\n        var x1 = coord1[0] / w1;\n        var y0 = coord0[1] / w0;\n        var y1 = coord1[1] / w1;\n        var z0 = coord0[2] / w0;\n        var z1 = coord1[2] / w1;\n\n\n        var t = z0 === z1 ? 0 : (targetZ - z0) / (z1 - z0);\n\n        return new Coordinate(\n            interp(x0, x1, t),\n            interp(y0, y1, t),\n            this.tileZoom);\n    },\n\n    coordinatePoint: function(coord) {\n        var matrix = this.coordinatePointMatrix(coord.zoom);\n        var p = vec4.transformMat4([], [coord.column, coord.row, 0, 1], matrix);\n        return new Point(p[0] / p[3], p[1] / p[3]);\n    },\n\n    coordinatePointMatrix: function(z) {\n        var proj = this.getProjMatrix();\n        var scale = this.worldSize / this.zoomScale(z);\n        mat4.scale(proj, proj, [scale, scale, 1]);\n        mat4.multiply(proj, this.getPixelMatrix(), proj);\n        return proj;\n    },\n\n    // converts gl coordinates -1..1 to pixels 0..width\n    getPixelMatrix: function() {\n        var m = mat4.create();\n        mat4.scale(m, m, [this.width / 2, -this.height / 2, 1]);\n        mat4.translate(m, m, [1, -1, 0]);\n        return m;\n    },\n\n    _constrain: function() {\n        if (!this.center) return;\n\n        var minY, maxY, minX, maxX, sy, sx, x2, y2,\n            size = this.size;\n\n        if (this.latRange) {\n            minY = this.latY(this.latRange[1]);\n            maxY = this.latY(this.latRange[0]);\n            sy = maxY - minY < size.y ? size.y / (maxY - minY) : 0;\n        }\n\n        if (this.lngRange) {\n            minX = this.lngX(this.lngRange[0]);\n            maxX = this.lngX(this.lngRange[1]);\n            sx = maxX - minX < size.x ? size.x / (maxX - minX) : 0;\n        }\n\n        // how much the map should scale to fit the screen into given latitude/longitude ranges\n        var s = Math.max(sx || 0, sy || 0);\n\n        if (s) {\n            this.center = this.unproject(new Point(\n                sx ? (maxX + minX) / 2 : this.x,\n                sy ? (maxY + minY) / 2 : this.y));\n            this.zoom += this.scaleZoom(s);\n            return;\n        }\n\n        if (this.latRange) {\n            var y = this.y,\n                h2 = size.y / 2;\n\n            if (y - h2 < minY) y2 = minY + h2;\n            if (y + h2 > maxY) y2 = maxY - h2;\n        }\n\n        if (this.lngRange) {\n            var x = this.x,\n                w2 = size.x / 2;\n\n            if (x - w2 < minX) x2 = minX + w2;\n            if (x + w2 > maxX) x2 = maxX - w2;\n        }\n\n        // pan the map if the screen goes off the range\n        if (x2 !== undefined || y2 !== undefined) {\n            this.center = this.unproject(new Point(\n                x2 !== undefined ? x2 : this.x,\n                y2 !== undefined ? y2 : this.y));\n        }\n    },\n\n    getProjMatrix: function() {\n        var m = new Float64Array(16);\n        mat4.perspective(m, 2 * Math.atan((this.height / 2) / this.altitude), this.width / this.height, 0.1, this.altitude + 1);\n\n        mat4.translate(m, m, [0, 0, -this.altitude]);\n\n        // After the rotateX, z values are in pixel units. Convert them to\n        // altitude unites. 1 altitude unit = the screen height.\n        mat4.scale(m, m, [1, -1, 1 / this.height]);\n\n        mat4.rotateX(m, m, this._pitch);\n        mat4.rotateZ(m, m, this.angle);\n        mat4.translate(m, m, [-this.x, -this.y, 0]);\n        return m;\n    }\n}","path":"js/geo/transform.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/geo/transform.js#L131-L134"},"params":[{"title":"param","description":null,"type":{"type":"NameExpression","name":"Number"},"name":"lat"}],"name":"latY","memberof":"Transform","scope":"instance","members":{"instance":[],"static":[]},"path":["latY"]},{"description":"Test whether the basic JavaScript and DOM features required for Mapbox GL are present.","tags":[{"title":"param","description":null,"type":{"type":"NameExpression","name":"Object"},"name":"options"},{"title":"name","name":"supported"},{"title":"memberof","description":"exports"},{"title":"static"}],"context":{"loc":{"start":{"line":55,"column":0},"end":{"line":109,"column":2}},"file":"/Users/tmcw/src/mapbox-gl-js/js/util/browser/browser.js","code":"'use strict';\n\nvar Canvas = require('./canvas');\n\nvar frame = window.requestAnimationFrame ||\n    window.mozRequestAnimationFrame ||\n    window.webkitRequestAnimationFrame ||\n    window.msRequestAnimationFrame;\n\nexports.frame = function(fn) {\n    return frame(fn);\n};\n\nvar cancel = window.cancelAnimationFrame ||\n    window.mozCancelAnimationFrame ||\n    window.webkitCancelAnimationFrame ||\n    window.msCancelAnimationFrame;\n\nexports.cancelFrame = function(id) {\n    cancel(id);\n};\n\nexports.timed = function (fn, dur, ctx) {\n    if (!dur) {\n        fn.call(ctx, 1);\n        return null;\n    }\n\n    var abort = false,\n        start = window.performance ? window.performance.now() : Date.now();\n\n    function tick(now) {\n        if (abort) return;\n        if (!window.performance) now = Date.now();\n\n        if (now >= start + dur) {\n            fn.call(ctx, 1);\n        } else {\n            fn.call(ctx, (now - start) / dur);\n            exports.frame(tick);\n        }\n    }\n\n    exports.frame(tick);\n\n    return function() { abort = true; };\n};\n\n/**\n * Test whether the basic JavaScript and DOM features required for Mapbox GL are present.\n * @param {Object} options\n * @param {Boolean} [options.failIfMajorPerformanceCaveat=false] If `true`, map creation will fail if the implementation determines that the performance of the created WebGL context would be dramatically lower than expected.\n * @return {Boolean} Returns true if Mapbox GL should be expected to work, and false if not.\n */\nexports.supported = function(options) {\n\n    var supports = [\n\n        function() { return typeof window !== 'undefined'; },\n\n        function() { return typeof document !== 'undefined'; },\n\n        function () {\n            return !!(Array.prototype &&\n                Array.prototype.every &&\n                Array.prototype.filter &&\n                Array.prototype.forEach &&\n                Array.prototype.indexOf &&\n                Array.prototype.lastIndexOf &&\n                Array.prototype.map &&\n                Array.prototype.some &&\n                Array.prototype.reduce &&\n                Array.prototype.reduceRight &&\n                Array.isArray);\n        },\n\n        function() {\n            return !!(Function.prototype && Function.prototype.bind) &&\n                !!(Object.keys &&\n                    Object.create &&\n                    Object.getPrototypeOf &&\n                    Object.getOwnPropertyNames &&\n                    Object.isSealed &&\n                    Object.isFrozen &&\n                    Object.isExtensible &&\n                    Object.getOwnPropertyDescriptor &&\n                    Object.defineProperty &&\n                    Object.defineProperties &&\n                    Object.seal &&\n                    Object.freeze &&\n                    Object.preventExtensions);\n        },\n\n        function() {\n            return 'JSON' in window && 'parse' in JSON && 'stringify' in JSON;\n        },\n\n        function() {\n            return new Canvas().supportsWebGLContext((options && options.failIfMajorPerformanceCaveat) || false);\n        },\n\n        function() { return 'Worker' in window; }\n    ];\n\n    for (var i = 0; i < supports.length; i++) {\n        if (!supports[i]()) return false;\n    }\n    return true;\n};\n\nexports.hardwareConcurrency = navigator.hardwareConcurrency || 8;\n\nObject.defineProperty(exports, 'devicePixelRatio', {\n    get: function() { return window.devicePixelRatio; }\n});","path":"js/util/browser/browser.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/util/browser/browser.js#L55-L109"},"params":[{"title":"param","description":null,"type":{"type":"NameExpression","name":"Object"},"name":"options"}],"name":"supported","memberof":"exports","scope":"static","members":{"instance":[],"static":[]},"path":["supported"]},{"description":"mapboxgl is a A WebGL JavaScript interactive maps library that can render\n[Mapbox vector tiles](https://www.mapbox.com/blog/vector-tiles/).","tags":[{"title":"module","description":null,"type":null,"name":"mapboxgl"},{"title":"summary","description":"WebGL JavaScript map library"},{"title":"name","name":"window"},{"title":"kind","kind":"module"}],"context":{"loc":{"start":{"line":10,"column":0},"end":{"line":46,"column":1}},"file":"/Users/tmcw/src/mapbox-gl-js","code":"'use strict';\n\n/**\n * mapboxgl is a A WebGL JavaScript interactive maps library that can render\n * [Mapbox vector tiles](https://www.mapbox.com/blog/vector-tiles/).\n *\n * @module mapboxgl\n * @summary WebGL JavaScript map library\n */\nif (typeof window === 'undefined') {\n    new (require('./source/worker'))(self); /*eslint no-new: 0*/\n} else {\n    // jshint -W079\n    var mapboxgl = module.exports = window.mapboxgl = {};\n\n    mapboxgl.Map = require('./ui/map');\n    mapboxgl.Navigation = require('./ui/control/navigation');\n    mapboxgl.Attribution = require('./ui/control/attribution');\n    mapboxgl.Popup = require('./ui/popup');\n\n    mapboxgl.GeoJSONSource = require('./source/geojson_source');\n    mapboxgl.VideoSource = require('./source/video_source');\n\n    mapboxgl.Style = require('./style/style');\n\n    mapboxgl.LatLng = require('./geo/lat_lng');\n    mapboxgl.LatLngBounds = require('./geo/lat_lng_bounds');\n    mapboxgl.Point = require('point-geometry');\n\n    mapboxgl.Evented = require('./util/evented');\n    mapboxgl.util = require('./util/util');\n\n    mapboxgl.supported = require('./util/browser').supported;\n\n    var ajax = require('./util/ajax');\n    mapboxgl.util.getJSON = ajax.getJSON;\n    mapboxgl.util.getArrayBuffer = ajax.getArrayBuffer;\n\n    var config = require('./util/config');\n    mapboxgl.config = config;\n\n    Object.defineProperty(mapboxgl, 'accessToken', {\n        get: function() { return config.ACCESS_TOKEN; },\n        set: function(token) { config.ACCESS_TOKEN = token; }\n    });\n}","path":"/Users/tmcw/src/mapbox-gl-js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05//Users/tmcw/src/mapbox-gl-js#L10-L46"},"name":"window","kind":"module","members":{"instance":[],"static":[]},"path":["window"]},{"description":"lat/lon <-> absolute pixel coords conversion","tags":[{"title":"param","description":null,"type":{"type":"NameExpression","name":"Number"},"name":"lon"},{"title":"name","name":"lngX"},{"title":"memberof","description":"Transform"},{"title":"instance"}],"context":{"loc":{"start":{"line":120,"column":4},"end":{"line":122,"column":5}},"file":"/Users/tmcw/src/mapbox-gl-js/js/geo/transform.js","code":"{\n    get minZoom() { return this._minZoom; },\n    set minZoom(zoom) {\n        this._minZoom = zoom;\n        this.zoom = Math.max(this.zoom, zoom);\n    },\n\n    get maxZoom() { return this._maxZoom; },\n    set maxZoom(zoom) {\n        this._maxZoom = zoom;\n        this.zoom = Math.min(this.zoom, zoom);\n    },\n\n    get worldSize() {\n        return this.tileSize * this.scale;\n    },\n\n    get centerPoint() {\n        return this.size._div(2);\n    },\n\n    get size() {\n        return new Point(this.width, this.height);\n    },\n\n    get bearing() {\n        return -this.angle / Math.PI * 180;\n    },\n    set bearing(bearing) {\n        this.angle = -wrap(bearing, -180, 180) * Math.PI / 180;\n    },\n\n    get pitch() {\n        return this._pitch / Math.PI * 180;\n    },\n    set pitch(pitch) {\n        this._pitch = Math.min(60, pitch) / 180 * Math.PI;\n    },\n\n    get altitude() {\n        return this._altitude;\n    },\n    set altitude(altitude) {\n        this._altitude = Math.max(0.75, altitude);\n    },\n\n    get zoom() { return this._zoom; },\n    set zoom(zoom) {\n        zoom = Math.min(Math.max(zoom, this.minZoom), this.maxZoom);\n        this._zoom = zoom;\n        this.scale = this.zoomScale(zoom);\n        this.tileZoom = Math.floor(zoom);\n        this.zoomFraction = zoom - this.tileZoom;\n        this._constrain();\n    },\n\n    zoomScale: function(zoom) { return Math.pow(2, zoom); },\n    scaleZoom: function(scale) { return Math.log(scale) / Math.LN2; },\n\n    project: function(latlng, worldSize) {\n        return new Point(\n            this.lngX(latlng.lng, worldSize),\n            this.latY(latlng.lat, worldSize));\n    },\n\n    unproject: function(point, worldSize) {\n        return new LatLng(\n            this.yLat(point.y, worldSize),\n            this.xLng(point.x, worldSize));\n    },\n\n    get x() { return this.lngX(this.center.lng); },\n    get y() { return this.latY(this.center.lat); },\n\n    get point() { return new Point(this.x, this.y); },\n\n    /**\n     * lat/lon <-> absolute pixel coords conversion\n     * @param {Number} lon\n     * @param {Number} [worldSize=this.worldSize]\n     * @returns {Number} pixel coordinate\n     * @private\n     */\n    lngX: function(lon, worldSize) {\n        return (180 + lon) * (worldSize || this.worldSize) / 360;\n    },\n    /**\n     * latitude to absolute y coord\n     *\n     * @param {Number} lat\n     * @param {Number} [worldSize=this.worldSize]\n     * @returns {Number} pixel coordinate\n     * @private\n     */\n    latY: function(lat, worldSize) {\n        var y = 180 / Math.PI * Math.log(Math.tan(Math.PI / 4 + lat * Math.PI / 360));\n        return (180 - y) * (worldSize || this.worldSize) / 360;\n    },\n\n    xLng: function(x, worldSize) {\n        return x * 360 / (worldSize || this.worldSize) - 180;\n    },\n    yLat: function(y, worldSize) {\n        var y2 = 180 - y * 360 / (worldSize || this.worldSize);\n        return 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90;\n    },\n\n    panBy: function(offset) {\n        var point = this.centerPoint._add(offset);\n        this.center = this.pointLocation(point);\n        this._constrain();\n    },\n\n    setLocationAtPoint: function(latlng, point) {\n        var c = this.locationCoordinate(latlng);\n        var coordAtPoint = this.pointCoordinate(point);\n        var coordCenter = this.pointCoordinate(this.centerPoint);\n\n        var translate = coordAtPoint._sub(c);\n        this.center = this.coordinateLocation(coordCenter._sub(translate));\n\n        this._constrain();\n    },\n\n    setZoomAround: function(zoom, center) {\n        var p = this.locationPoint(center);\n        this.zoom = zoom;\n        this.setLocationAtPoint(center, p);\n    },\n\n    setBearingAround: function(bearing, center) {\n        var p = this.locationPoint(center);\n        this.bearing = bearing;\n        this.setLocationAtPoint(center, p);\n    },\n\n    locationPoint: function(latlng) {\n        return this.coordinatePoint(this.locationCoordinate(latlng));\n    },\n\n    pointLocation: function(p) {\n        return this.coordinateLocation(this.pointCoordinate(p));\n    },\n\n    locationCoordinate: function(latlng) {\n        var k = this.zoomScale(this.tileZoom) / this.worldSize;\n        return new Coordinate(\n            this.lngX(latlng.lng) * k,\n            this.latY(latlng.lat) * k,\n            this.tileZoom);\n    },\n\n    coordinateLocation: function(coord) {\n        var worldSize = this.zoomScale(coord.zoom);\n        return new LatLng(\n            this.yLat(coord.row, worldSize),\n            this.xLng(coord.column, worldSize));\n    },\n\n    pointCoordinate: function(p, targetZ) {\n\n        if (targetZ === undefined) targetZ = 0;\n\n        var matrix = this.coordinatePointMatrix(this.tileZoom);\n        var inverted = mat4.invert(new Float64Array(16), matrix);\n\n        if (!inverted) throw \"failed to invert matrix\";\n\n        // since we don't know the correct projected z value for the point,\n        // unproject two points to get a line and then find the point on that\n        // line with z=0\n\n        var coord0 = vec4.transformMat4([], [p.x, p.y, 0, 1], inverted);\n        var coord1 = vec4.transformMat4([], [p.x, p.y, 1, 1], inverted);\n\n        var w0 = coord0[3];\n        var w1 = coord1[3];\n        var x0 = coord0[0] / w0;\n        var x1 = coord1[0] / w1;\n        var y0 = coord0[1] / w0;\n        var y1 = coord1[1] / w1;\n        var z0 = coord0[2] / w0;\n        var z1 = coord1[2] / w1;\n\n\n        var t = z0 === z1 ? 0 : (targetZ - z0) / (z1 - z0);\n\n        return new Coordinate(\n            interp(x0, x1, t),\n            interp(y0, y1, t),\n            this.tileZoom);\n    },\n\n    coordinatePoint: function(coord) {\n        var matrix = this.coordinatePointMatrix(coord.zoom);\n        var p = vec4.transformMat4([], [coord.column, coord.row, 0, 1], matrix);\n        return new Point(p[0] / p[3], p[1] / p[3]);\n    },\n\n    coordinatePointMatrix: function(z) {\n        var proj = this.getProjMatrix();\n        var scale = this.worldSize / this.zoomScale(z);\n        mat4.scale(proj, proj, [scale, scale, 1]);\n        mat4.multiply(proj, this.getPixelMatrix(), proj);\n        return proj;\n    },\n\n    // converts gl coordinates -1..1 to pixels 0..width\n    getPixelMatrix: function() {\n        var m = mat4.create();\n        mat4.scale(m, m, [this.width / 2, -this.height / 2, 1]);\n        mat4.translate(m, m, [1, -1, 0]);\n        return m;\n    },\n\n    _constrain: function() {\n        if (!this.center) return;\n\n        var minY, maxY, minX, maxX, sy, sx, x2, y2,\n            size = this.size;\n\n        if (this.latRange) {\n            minY = this.latY(this.latRange[1]);\n            maxY = this.latY(this.latRange[0]);\n            sy = maxY - minY < size.y ? size.y / (maxY - minY) : 0;\n        }\n\n        if (this.lngRange) {\n            minX = this.lngX(this.lngRange[0]);\n            maxX = this.lngX(this.lngRange[1]);\n            sx = maxX - minX < size.x ? size.x / (maxX - minX) : 0;\n        }\n\n        // how much the map should scale to fit the screen into given latitude/longitude ranges\n        var s = Math.max(sx || 0, sy || 0);\n\n        if (s) {\n            this.center = this.unproject(new Point(\n                sx ? (maxX + minX) / 2 : this.x,\n                sy ? (maxY + minY) / 2 : this.y));\n            this.zoom += this.scaleZoom(s);\n            return;\n        }\n\n        if (this.latRange) {\n            var y = this.y,\n                h2 = size.y / 2;\n\n            if (y - h2 < minY) y2 = minY + h2;\n            if (y + h2 > maxY) y2 = maxY - h2;\n        }\n\n        if (this.lngRange) {\n            var x = this.x,\n                w2 = size.x / 2;\n\n            if (x - w2 < minX) x2 = minX + w2;\n            if (x + w2 > maxX) x2 = maxX - w2;\n        }\n\n        // pan the map if the screen goes off the range\n        if (x2 !== undefined || y2 !== undefined) {\n            this.center = this.unproject(new Point(\n                x2 !== undefined ? x2 : this.x,\n                y2 !== undefined ? y2 : this.y));\n        }\n    },\n\n    getProjMatrix: function() {\n        var m = new Float64Array(16);\n        mat4.perspective(m, 2 * Math.atan((this.height / 2) / this.altitude), this.width / this.height, 0.1, this.altitude + 1);\n\n        mat4.translate(m, m, [0, 0, -this.altitude]);\n\n        // After the rotateX, z values are in pixel units. Convert them to\n        // altitude unites. 1 altitude unit = the screen height.\n        mat4.scale(m, m, [1, -1, 1 / this.height]);\n\n        mat4.rotateX(m, m, this._pitch);\n        mat4.rotateZ(m, m, this.angle);\n        mat4.translate(m, m, [-this.x, -this.y, 0]);\n        return m;\n    }\n}","path":"js/geo/transform.js","github":"https://github.com/mapbox/mapbox-gl-js/blob/f23285cc5fc760921f455f601d113a52d7401a05/js/geo/transform.js#L120-L122"},"params":[{"title":"param","description":null,"type":{"type":"NameExpression","name":"Number"},"name":"lon"}],"name":"lngX","memberof":"Transform","scope":"instance","members":{"instance":[],"static":[]},"path":["lngX"]}]