/*!
 * maptalks v0.49.5
 * LICENSE : BSD-3-Clause
 * (c) 2016-2021 maptalks.org
 */
(function(global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
        typeof define === 'function' && define.amd ? define(['exports'], factory) :
        (factory((global.maptalks = {})));
}(this, (function(exports) {
    'use strict';

    var version = "0.49.5";

    var INTERNAL_LAYER_PREFIX = '_maptalks__internal_layer_';
    var GEOMETRY_COLLECTION_TYPES = ['MultiPoint', 'MultiLineString', 'MultiPolygon', 'GeometryCollection'];
    var GEOJSON_TYPES = ['FeatureCollection', 'Feature', 'Point', 'LineString', 'Polygon'].concat(GEOMETRY_COLLECTION_TYPES);
    var RESOURCE_PROPERTIES = ['markerFile', 'polygonPatternFile', 'linePatternFile', 'markerFillPatternFile', 'markerLinePatternFile'];
    var RESOURCE_SIZE_PROPERTIES = [
        ['markerWidth', 'markerHeight'],
        [],
        [null, 'lineWidth'],
        [],
        [null, 'markerLineWidth']
    ];
    var NUMERICAL_PROPERTIES = {
        'lineWidth': 1,
        'lineOpacity': 1,
        'lineDx': 1,
        'lineDy': 1,
        'polygonOpacity': 1,
        'markerWidth': 1,
        'markerHeight': 1,
        'markerDx': 1,
        'markerDy': 1,
        'markerOpacity': 1,
        'markerFillOpacity': 1,
        'markerLineWidth': 1,
        'markerLineOpacity': 1,
        'textSize': 1,
        'textOpacity': 1,
        'textHaloRadius': 1,
        'textWrapWidth': 1,
        'textLineSpacing': 1,
        'textDx': 1,
        'textDy': 1
    };
    var COLOR_PROPERTIES = ['lineColor', 'polygonFill', 'markerFill', 'markerLineColor', 'textFill'];
    var DEFAULT_TEXT_SIZE = 14;

    function now() {
        return Date.now();
    }

    function extend(dest) {
        for (var i = 1; i < arguments.length; i++) {
            var src = arguments[i];

            for (var k in src) {
                dest[k] = src[k];
            }
        }

        return dest;
    }

    function isNil(obj) {
        return obj == null;
    }

    function isNumber(val) {
        return typeof val === 'number' && !isNaN(val);
    }

    function isInteger(n) {
        return (n | 0) === n;
    }

    function isObject(obj) {
        return typeof obj === 'object' && !!obj;
    }

    function isString(obj) {
        if (isNil(obj)) {
            return false;
        }

        return typeof obj === 'string' || obj.constructor !== null && obj.constructor === String;
    }

    function isFunction(obj) {
        if (isNil(obj)) {
            return false;
        }

        return typeof obj === 'function' || obj.constructor !== null && obj.constructor === Function;
    }
    var hasOwnProperty = Object.prototype.hasOwnProperty;

    function hasOwn(obj, key) {
        return hasOwnProperty.call(obj, key);
    }

    function join(arr, seperator) {
        if (arr.join) {
            return arr.join(seperator || ',');
        } else {
            return Array.prototype.join.call(arr, seperator || ',');
        }
    }

    function isEmpty(object) {
        var property;

        for (property in object) {
            return false;
        }

        return !property;
    }
    var pi = Math.PI / 180;

    function toRadian(d) {
        return d * pi;
    }

    function toDegree(r) {
        return r / pi;
    }

    var IS_NODE = Object.prototype.toString.call(typeof process !== 'undefined' ? process : 0) === '[object process]' && !process.versions['electron'] && !process.versions['nw'] && !process.versions['node-webkit'];

    var requestAnimFrame, cancelAnimFrame;

    (function() {
        if (IS_NODE) {
            requestAnimFrame = function requestAnimFrame(fn) {
                return setTimeout(fn, 16);
            };

            cancelAnimFrame = clearTimeout;
            return;
        }

        var requestFn, cancelFn;
        var timeToCall = 1000 / 30;

        function timeoutDefer(fn) {
            return setTimeout(fn, timeToCall);
        }

        function getPrefixed(name) {
            return window['webkit' + name] || window['moz' + name] || window['ms' + name];
        }

        if (typeof window != 'undefined') {
            requestFn = window['requestAnimationFrame'] || getPrefixed('RequestAnimationFrame') || timeoutDefer;

            cancelFn = window['cancelAnimationFrame'] || getPrefixed('CancelAnimationFrame') || getPrefixed('CancelRequestAnimationFrame') || function(id) {
                window.clearTimeout(id);
            };
        } else {
            requestFn = timeoutDefer;
            cancelFn = clearTimeout;
        }

        requestAnimFrame = function requestAnimFrame(fn) {
            return requestFn(fn);
        };

        cancelAnimFrame = function cancelAnimFrame(id) {
            if (id) {
                cancelFn(id);
            }
        };
    })();

    function isSVG(url) {
        var prefix = 'data:image/svg+xml';

        if (url.length > 4 && url.slice(-4) === '.svg') {
            return 1;
        } else if (url.slice(0, prefix.length) === prefix) {
            return 2;
        }

        return 0;
    }

    function loadImage(img, imgDesc) {
        if (IS_NODE && loadImage.node) {
            loadImage.node(img, imgDesc);
            return;
        }

        img.src = imgDesc[0];
    }
    var uid = 0;

    function UID() {
        return uid++;
    }
    var GUID = UID;

    function parseJSON(str) {
        if (!str || !isString(str)) {
            return str;
        }

        return JSON.parse(str);
    }

    function pushIn(dest) {
        for (var i = 1; i < arguments.length; i++) {
            var src = arguments[i];

            if (src) {
                for (var ii = 0, ll = src.length; ii < ll; ii++) {
                    dest.push(src[ii]);
                }
            }
        }

        return dest.length;
    }

    function removeFromArray(obj, array) {
        var i = array.indexOf(obj);

        if (i > -1) {
            array.splice(i, 1);
        }
    }

    function forEachCoord(arr, fn, context) {
        if (!Array.isArray(arr)) {
            return context ? fn.call(context, arr) : fn(arr);
        }

        var result = [];
        var p, pp;

        for (var i = 0, len = arr.length; i < len; i++) {
            p = arr[i];

            if (isNil(p)) {
                result.push(null);
                continue;
            }

            if (Array.isArray(p)) {
                result.push(forEachCoord(p, fn, context));
            } else {
                pp = context ? fn.call(context, p) : fn(p);
                result.push(pp);
            }
        }

        return result;
    }

    function getValueOrDefault(v, d) {
        return v === undefined ? d : v;
    }

    function sign(x) {
        if (Math.sign) {
            return Math.sign(x);
        }

        x = +x;

        if (x === 0 || isNaN(x)) {
            return Number(x);
        }

        return x > 0 ? 1 : -1;
    }

    function log2(x) {
        if (Math.log2) {
            return Math.log2(x);
        }

        var v = Math.log(x) * Math.LOG2E;
        var rounded = Math.round(v);

        if (Math.abs(rounded - v) < 1E-14) {
            return rounded;
        } else {
            return v;
        }
    }

    function interpolate(a, b, t) {
        return a * (1 - t) + b * t;
    }

    function wrap(n, min, max) {
        if (n === max || n === min) {
            return n;
        }

        var d = max - min;
        var w = ((n - min) % d + d) % d + min;
        return w;
    }

    function clamp(n, min, max) {
        return Math.min(max, Math.max(min, n));
    }

    function isArrayHasData(obj) {
        return Array.isArray(obj) && obj.length > 0;
    }
    var urlPattern = /^([a-z][a-z\d+\-.]*:)?\/\//i;

    function isURL(url) {
        return urlPattern.test(url);
    }
    var cssUrlReWithQuote = /^url\((['"])(.+)\1\)$/i;
    var cssUrlRe = /^url\(([^'"].*[^'"])\)$/i;

    function isCssUrl(str) {
        if (!isString(str)) {
            return 0;
        }

        if (cssUrlRe.test(str)) {
            return 1;
        }

        if (cssUrlReWithQuote.test(str)) {
            return 2;
        }

        return 3;
    }

    function extractCssUrl(str) {
        var test = isCssUrl(str);
        var matches;

        if (test === 3) {
            return str;
        } else if (test === 1) {
            matches = cssUrlRe.exec(str);
            return matches[1];
        } else if (test === 2) {
            matches = cssUrlReWithQuote.exec(str);
            return matches[2];
        } else {
            return str;
        }
    }
    var b64chrs = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';

    function btoa(input) {
        if (typeof window !== 'undefined' && window.btoa) {
            return window.btoa(input);
        }

        var str = String(input);
        var output = '';

        for (var block, charCode, idx = 0, map = b64chrs; str.charAt(idx | 0) || (map = '=', idx % 1); output += map.charAt(63 & block >> 8 - idx % 1 * 8)) {
            charCode = str.charCodeAt(idx += 3 / 4);

            if (charCode > 0xFF) {
                throw new Error('\'btoa\' failed: The string to be encoded contains characters outside of the Latin1 range.');
            }

            block = block << 8 | charCode;
        }

        return output;
    }

    function b64toBlob(b64Data, contentType) {
        var byteCharacters = atob(b64Data);
        var arraybuffer = new ArrayBuffer(byteCharacters.length);
        var view = new Uint8Array(arraybuffer);

        for (var i = 0; i < byteCharacters.length; i++) {
            view[i] = byteCharacters.charCodeAt(i) & 0xff;
        }

        var blob = new Blob([arraybuffer], {
            type: contentType
        });
        return blob;
    }

    function computeDegree(x0, y0, x1, y1) {
        var dx = x1 - x0;
        var dy = y1 - y0;
        return Math.atan2(dy, dx);
    }
    var emptyImageUrl = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';

    function equalMapView(obj1, obj2) {
        if (!obj1 && !obj2) {
            return true;
        } else if (!obj1 || !obj2) {
            return false;
        }

        for (var p in obj1) {
            if (p === 'center') {
                if (!obj2[p] || !approx(obj1[p][0], obj2[p][0]) || !approx(obj1[p][1], obj2[p][1])) {
                    return false;
                }
            } else if (obj1[p] !== obj2[p]) {
                return false;
            }
        }

        return true;
    }

    function approx(val, expected, delta) {
        if (delta == null) {
            delta = 1e-6;
        }

        return val >= expected - delta && val <= expected + delta;
    }

    function flash(interval, count, cb, context) {
        if (!interval) {
            interval = 100;
        }

        if (!count) {
            count = 4;
        }

        var me = this;
        count *= 2;

        if (this._flashTimeout) {
            clearTimeout(this._flashTimeout);
        }

        function flashGeo() {
            if (count === 0) {
                me.show();

                if (cb) {
                    if (context) {
                        cb.call(context);
                    } else {
                        cb();
                    }
                }

                return;
            }

            if (count % 2 === 0) {
                me.hide();
            } else {
                me.show();
            }

            count--;
            me._flashTimeout = setTimeout(flashGeo, interval);
        }

        this._flashTimeout = setTimeout(flashGeo, interval);
        return this;
    }

    function _defaults(obj, defaults) {
        var keys = Object.getOwnPropertyNames(defaults);

        for (var i = 0; i < keys.length; i++) {
            var key = keys[i];
            var value = Object.getOwnPropertyDescriptor(defaults, key);

            if (value && value.configurable && obj[key] === undefined) {
                Object.defineProperty(obj, key, value);
            }
        }

        return obj;
    }

    var types = ['Unknown', 'Point', 'LineString', 'Polygon', 'MultiPoint', 'MultiLineString', 'MultiPolygon', 'GeometryCollection'];

    function createFilter(filter) {
        return new Function('f', "var p = (f && f.properties || {}); return " + compile(filter));
    }

    function compile(filter) {
        if (!filter) return 'true';
        var op = filter[0];
        if (filter.length <= 1) return op === 'any' ? 'false' : 'true';
        var str = op === '==' ? compileComparisonOp(filter[1], filter[2], '===', false) : op === '!=' ? compileComparisonOp(filter[1], filter[2], '!==', false) : op === '<' || op === '>' || op === '<=' || op === '>=' ? compileComparisonOp(filter[1], filter[2], op, true) : op === 'any' ? compileLogicalOp(filter.slice(1), '||') : op === 'all' ? compileLogicalOp(filter.slice(1), '&&') : op === 'none' ? compileNegation(compileLogicalOp(filter.slice(1), '||')) : op === 'in' ? compileInOp(filter[1], filter.slice(2)) : op === '!in' ? compileNegation(compileInOp(filter[1], filter.slice(2))) : op === 'has' ? compileHasOp(filter[1]) : op === '!has' ? compileNegation(compileHasOp(filter[1])) : 'true';
        return "(" + str + ")";
    }

    function compilePropertyReference(property) {
        return property[0] === '$' ? 'f.' + property.substring(1) : 'p[' + JSON.stringify(property) + ']';
    }

    function compileComparisonOp(property, value, op, checkType) {
        var left = compilePropertyReference(property);
        var right = property === '$type' ? types.indexOf(value) : JSON.stringify(value);
        return (checkType ? "typeof " + left + "=== typeof " + right + "&&" : '') + left + op + right;
    }

    function compileLogicalOp(expressions, op) {
        return expressions.map(compile).join(op);
    }

    function compileInOp(property, values) {
        if (property === '$type') values = values.map(function(value) {
            return types.indexOf(value);
        });
        var left = JSON.stringify(values.sort(compare));
        var right = compilePropertyReference(property);
        if (values.length <= 200) return left + ".indexOf(" + right + ") !== -1";
        return "function(v, a, i, j) {\n        while (i <= j) { var m = (i + j) >> 1;\n            if (a[m] === v) return true; if (a[m] > v) j = m - 1; else i = m + 1;\n        }\n    return false; }(" + right + ", " + left + ",0," + (values.length - 1) + ")";
    }

    function compileHasOp(property) {
        return property === '$id' ? '"id" in f' : JSON.stringify(property) + " in p";
    }

    function compileNegation(expression) {
        return "!(" + expression + ")";
    }

    function compare(a, b) {
        return a < b ? -1 : a > b ? 1 : 0;
    }

    function getFilterFeature(geometry) {
        var json = geometry._toJSON(),
            g = json['feature'];

        g['type'] = types.indexOf(g['geometry']['type']);
        g['subType'] = json['subType'];
        return g;
    }

    function compileStyle(styles) {
        if (!Array.isArray(styles)) {
            return compileStyle([styles]);
        }

        var compiled = [];

        for (var i = 0; i < styles.length; i++) {
            var filter = void 0;

            if (styles[i]['filter'] === true) {
                filter = function filter() {
                    return true;
                };
            } else {
                filter = createFilter(styles[i]['filter']);
            }

            compiled.push(extend$1({}, styles[i], {
                filter: filter
            }));
        }

        return compiled;
    }

    function extend$1(dest) {
        for (var i = 1; i < arguments.length; i++) {
            var src = arguments[i];

            for (var k in src) {
                dest[k] = src[k];
            }
        }

        return dest;
    }

    function createFunction(parameters, defaultType) {
        var fun;
        var isFeatureConstant, isZoomConstant;

        if (!isFunctionDefinition(parameters)) {
            fun = function fun() {
                return parameters;
            };

            isFeatureConstant = true;
            isZoomConstant = true;
        } else {
            var zoomAndFeatureDependent = parameters.stops && typeof parameters.stops[0][0] === 'object';
            var featureDependent = zoomAndFeatureDependent || parameters.property !== undefined;
            var zoomDependent = zoomAndFeatureDependent || !featureDependent;
            var type = parameters.type || defaultType || 'exponential';
            var innerFun;

            if (type === 'exponential') {
                innerFun = evaluateExponentialFunction;
            } else if (type === 'interval') {
                innerFun = evaluateIntervalFunction;
            } else if (type === 'categorical') {
                innerFun = evaluateCategoricalFunction;
            } else if (type === 'identity') {
                innerFun = evaluateIdentityFunction;
            } else {
                throw new Error('Unknown function type "' + type + '"');
            }

            if (zoomAndFeatureDependent) {
                var featureFunctions = {};
                var featureFunctionStops = [];

                for (var s = 0; s < parameters.stops.length; s++) {
                    var stop = parameters.stops[s];

                    if (featureFunctions[stop[0].zoom] === undefined) {
                        featureFunctions[stop[0].zoom] = {
                            zoom: stop[0].zoom,
                            type: parameters.type,
                            property: parameters.property,
                            default: parameters.default,
                            stops: []
                        };
                    }

                    featureFunctions[stop[0].zoom].stops.push([stop[0].value, stop[1]]);
                }

                for (var z in featureFunctions) {
                    featureFunctionStops.push([featureFunctions[z].zoom, createFunction(featureFunctions[z])]);
                }

                fun = function fun(zoom, feature) {
                    var value = evaluateExponentialFunction({
                        stops: featureFunctionStops,
                        base: parameters.base
                    }, zoom)(zoom, feature);
                    return typeof value === 'function' ? value(zoom, feature) : value;
                };

                isFeatureConstant = false;
                isZoomConstant = false;
            } else if (zoomDependent) {
                fun = function fun(zoom) {
                    var value = innerFun(parameters, zoom);
                    return typeof value === 'function' ? value(zoom) : value;
                };

                isFeatureConstant = true;
                isZoomConstant = false;
            } else {
                fun = function fun(zoom, feature) {
                    var value = innerFun(parameters, feature ? feature[parameters.property] : null);
                    return typeof value === 'function' ? value(zoom, feature) : value;
                };

                isFeatureConstant = false;
                isZoomConstant = true;
            }
        }

        fun.isZoomConstant = isZoomConstant;
        fun.isFeatureConstant = isFeatureConstant;
        return fun;
    }

    function coalesce(a, b, c) {
        if (a !== undefined) return a;
        if (b !== undefined) return b;
        if (c !== undefined) return c;
        return null;
    }

    function evaluateCategoricalFunction(parameters, input) {
        for (var i = 0; i < parameters.stops.length; i++) {
            if (input === parameters.stops[i][0]) {
                return parameters.stops[i][1];
            }
        }

        return parameters.default;
    }

    function evaluateIntervalFunction(parameters, input) {
        for (var i = 0; i < parameters.stops.length; i++) {
            if (input < parameters.stops[i][0]) break;
        }

        return parameters.stops[Math.max(i - 1, 0)][1];
    }

    function evaluateExponentialFunction(parameters, input) {
        var base = parameters.base !== undefined ? parameters.base : 1;
        var i = 0;

        while (true) {
            if (i >= parameters.stops.length) break;
            else if (input <= parameters.stops[i][0]) break;
            else i++;
        }

        if (i === 0) {
            return parameters.stops[i][1];
        } else if (i === parameters.stops.length) {
            return parameters.stops[i - 1][1];
        } else {
            return interpolate$1(input, base, parameters.stops[i - 1][0], parameters.stops[i][0], parameters.stops[i - 1][1], parameters.stops[i][1]);
        }
    }

    function evaluateIdentityFunction(parameters, input) {
        return coalesce(input, parameters.default);
    }

    function interpolate$1(input, base, inputLower, inputUpper, outputLower, outputUpper) {
        if (typeof outputLower === 'function') {
            return function() {
                var evaluatedLower = outputLower.apply(undefined, arguments);
                var evaluatedUpper = outputUpper.apply(undefined, arguments);
                return interpolate$1(input, base, inputLower, inputUpper, evaluatedLower, evaluatedUpper);
            };
        } else if (outputLower.length) {
            return interpolateArray(input, base, inputLower, inputUpper, outputLower, outputUpper);
        } else {
            return interpolateNumber(input, base, inputLower, inputUpper, outputLower, outputUpper);
        }
    }

    function interpolateNumber(input, base, inputLower, inputUpper, outputLower, outputUpper) {
        var difference = inputUpper - inputLower;
        var progress = input - inputLower;
        var ratio;

        if (base === 1) {
            ratio = progress / difference;
        } else {
            ratio = (Math.pow(base, progress) - 1) / (Math.pow(base, difference) - 1);
        }

        return outputLower * (1 - ratio) + outputUpper * ratio;
    }

    function interpolateArray(input, base, inputLower, inputUpper, outputLower, outputUpper) {
        var output = [];

        for (var i = 0; i < outputLower.length; i++) {
            output[i] = interpolateNumber(input, base, inputLower, inputUpper, outputLower[i], outputUpper[i]);
        }

        return output;
    }

    function isFunctionDefinition(obj) {
        return obj && typeof obj === 'object' && (obj.stops || obj.property && obj.type === 'identity');
    }

    function hasFunctionDefinition(obj) {
        for (var p in obj) {
            if (isFunctionDefinition(obj[p])) {
                return true;
            }
        }

        return false;
    }

    function interpolated(parameters) {
        return createFunction1(parameters, 'exponential');
    }

    function piecewiseConstant(parameters) {
        return createFunction1(parameters, 'interval');
    }

    function loadFunctionTypes(obj, argFn) {
        if (!obj) {
            return null;
        }

        var hit = false;

        if (Array.isArray(obj)) {
            var multResult = [],
                loaded;

            for (var i = 0; i < obj.length; i++) {
                loaded = loadFunctionTypes(obj[i], argFn);

                if (!loaded) {
                    multResult.push(obj[i]);
                } else {
                    multResult.push(loaded);
                    hit = true;
                }
            }

            return hit ? multResult : obj;
        }

        var result = {
                '__fn_types_loaded': true
            },
            props = [],
            p;

        for (p in obj) {
            if (obj.hasOwnProperty(p)) {
                props.push(p);
            }
        }

        var buildFn = function buildFn(p) {
            Object.defineProperty(result, p, {
                get: function get() {
                    if (!this['__fn_' + p]) {
                        this['__fn_' + p] = interpolated(this['_' + p]);
                    }

                    return this['__fn_' + p].apply(this, argFn());
                },
                set: function set(v) {
                    this['_' + p] = v;
                },
                configurable: true,
                enumerable: true
            });
        };

        for (var _i = 0, len = props.length; _i < len; _i++) {
            p = props[_i];

            if (isFunctionDefinition(obj[p])) {
                hit = true;
                result['_' + p] = obj[p];
                buildFn(p);
            } else {
                result[p] = obj[p];
            }
        }

        return hit ? result : obj;
    }

    function getFunctionTypeResources(t) {
        if (!t || !t.stops) {
            return [];
        }

        var res = [];

        for (var i = 0, l = t.stops.length; i < l; i++) {
            res.push(t.stops[i][1]);
        }

        return res;
    }

    function createFunction1(parameters, defaultType) {
        if (!isFunctionDefinition(parameters)) {
            return function() {
                return parameters;
            };
        }

        parameters = JSON.parse(JSON.stringify(parameters));
        var isZoomConstant = true;
        var isFeatureConstant = true;
        var stops = parameters.stops;

        if (stops) {
            for (var i = 0; i < stops.length; i++) {
                if (isFunctionDefinition(stops[i][1])) {
                    var _fn = createFunction1(stops[i][1], defaultType);

                    isZoomConstant = isZoomConstant && _fn.isZoomConstant;
                    isFeatureConstant = isFeatureConstant && _fn.isFeatureConstant;
                    stops[i] = [stops[i][0], _fn];
                }
            }
        }

        var fn = createFunction(parameters, defaultType);
        fn.isZoomConstant = isZoomConstant && fn.isZoomConstant;
        fn.isFeatureConstant = isFeatureConstant && fn.isFeatureConstant;
        return fn;
    }



    var index = /*#__PURE__*/ Object.freeze({
        createFilter: createFilter,
        getFilterFeature: getFilterFeature,
        compileStyle: compileStyle,
        isFunctionDefinition: isFunctionDefinition,
        hasFunctionDefinition: hasFunctionDefinition,
        interpolated: interpolated,
        piecewiseConstant: piecewiseConstant,
        loadFunctionTypes: loadFunctionTypes,
        getFunctionTypeResources: getFunctionTypeResources
    });

    function translateToSVGStyles(s) {
        var result = {
            'stroke': {
                'stroke': s['markerLineColor'],
                'stroke-width': s['markerLineWidth'],
                'stroke-opacity': s['markerLineOpacity'],
                'stroke-dasharray': null,
                'stroke-linecap': 'butt',
                'stroke-linejoin': 'round'
            },
            'fill': {
                'fill': s['markerFill'],
                'fill-opacity': s['markerFillOpacity']
            }
        };

        if (result['stroke']['stroke-width'] === 0) {
            result['stroke']['stroke-opacity'] = 0;
        }

        return result;
    }

    function getMarkerPathBase64(symbol, width, height) {
        if (!symbol['markerPath']) {
            return null;
        }

        var op = 1;
        var styles = translateToSVGStyles(symbol);

        if (isNumber(symbol['markerOpacity'])) {
            op = symbol['markerOpacity'];
        }

        if (isNumber(symbol['opacity'])) {
            op *= symbol['opacity'];
        }

        var svgStyles = {};

        if (styles) {
            for (var p in styles['stroke']) {
                if (styles['stroke'].hasOwnProperty(p)) {
                    if (!isNil(styles['stroke'][p])) {
                        svgStyles[p] = styles['stroke'][p];
                    }
                }
            }

            for (var _p in styles['fill']) {
                if (styles['fill'].hasOwnProperty(_p)) {
                    if (!isNil(styles['fill'][_p])) {
                        svgStyles[_p] = styles['fill'][_p];
                    }
                }
            }
        }

        var pathes = Array.isArray(symbol['markerPath']) ? symbol['markerPath'] : [symbol['markerPath']];
        var path;
        var pathesToRender = [];

        for (var i = 0; i < pathes.length; i++) {
            path = isString(pathes[i]) ? {
                'path': pathes[i]
            } : pathes[i];
            path = extend({}, path, svgStyles);
            path['d'] = path['path'];
            delete path['path'];
            pathesToRender.push(path);
        }

        var svg = ['<svg version="1.1"', 'xmlns="http://www.w3.org/2000/svg"'];

        if (op < 1) {
            svg.push('opacity="' + op + '"');
        }

        if (symbol['markerPathWidth'] && symbol['markerPathHeight']) {
            svg.push('viewBox="0 0 ' + symbol['markerPathWidth'] + ' ' + symbol['markerPathHeight'] + '"');
        }

        svg.push('preserveAspectRatio="none"');

        if (width) {
            svg.push('width="' + width + '"');
        }

        if (height) {
            svg.push('height="' + height + '"');
        }

        svg.push('><defs></defs>');

        for (var _i = 0; _i < pathesToRender.length; _i++) {
            var strPath = '<path ';

            for (var _p2 in pathesToRender[_i]) {
                if (pathesToRender[_i].hasOwnProperty(_p2)) {
                    strPath += ' ' + _p2 + '="' + pathesToRender[_i][_p2] + '"';
                }
            }

            strPath += '></path>';
            svg.push(strPath);
        }

        svg.push('</svg>');
        var b64 = 'data:image/svg+xml;base64,' + btoa(svg.join(' '));
        return b64;
    }

    function getExternalResources(symbol, toAbsolute) {
        if (!symbol) {
            return [];
        }

        var symbols = symbol;

        if (!Array.isArray(symbol)) {
            symbols = [symbol];
        }

        var resources = [];
        var props = RESOURCE_PROPERTIES;
        var res, resSizeProp;
        var w, h;

        for (var i = symbols.length - 1; i >= 0; i--) {
            symbol = symbols[i];

            if (!symbol) {
                continue;
            }

            if (toAbsolute) {
                symbol = convertResourceUrl(symbol);
            }

            for (var ii = 0; ii < props.length; ii++) {
                res = symbol[props[ii]];

                if (isFunctionDefinition(res)) {
                    res = getFunctionTypeResources(res);
                }

                if (!res) {
                    continue;
                }

                if (!Array.isArray(res)) {
                    res = [res];
                }

                for (var iii = 0; iii < res.length; iii++) {
                    if (res[iii].slice(0, 4) === 'url(') {
                        res[iii] = extractCssUrl(res[iii]);
                    }

                    resSizeProp = RESOURCE_SIZE_PROPERTIES[ii];
                    resources.push([res[iii], symbol[resSizeProp[0]], symbol[resSizeProp[1]]]);
                }
            }

            if (symbol['markerType'] === 'path' && symbol['markerPath']) {
                w = isFunctionDefinition(symbol['markerWidth']) ? 200 : symbol['markerWidth'];
                h = isFunctionDefinition(symbol['markerHeight']) ? 200 : symbol['markerHeight'];

                if (isFunctionDefinition(symbol['markerPath'])) {
                    res = getFunctionTypeResources(symbol['markerPath']);
                    var path = symbol['markerPath'];

                    for (var _iii = 0; _iii < res.length; _iii++) {
                        symbol['markerPath'] = res[_iii];
                        resources.push([getMarkerPathBase64(symbol), w, h]);
                    }

                    symbol['markerPath'] = path;
                } else {
                    resources.push([getMarkerPathBase64(symbol), w, h]);
                }
            }
        }

        return resources;
    }

    function convertResourceUrl(symbol) {
        if (!symbol) {
            return null;
        }

        var s = symbol;

        if (IS_NODE) {
            return s;
        }

        var props = RESOURCE_PROPERTIES;
        var res;

        for (var ii = 0, len = props.length; ii < len; ii++) {
            res = s[props[ii]];

            if (!res) {
                continue;
            }

            s[props[ii]] = _convertUrl(res);
        }

        return s;
    }

    function _convertUrl(res) {
        if (isFunctionDefinition(res)) {
            var stops = res.stops;

            for (var i = 0; i < stops.length; i++) {
                stops[i][1] = _convertUrl(stops[i][1]);
            }

            return res;
        }

        if (res.slice(0, 4) === 'url(') {
            res = extractCssUrl(res);
        }

        return res;
    }

    function isGradient(g) {
        return g && g['colorStops'];
    }

    function getGradientStamp(g) {
        var keys = [g['type']];

        if (g['places']) {
            keys.push(g['places'].join());
        }

        if (g['colorStops']) {
            var stops = [];

            for (var i = g['colorStops'].length - 1; i >= 0; i--) {
                stops.push(g['colorStops'][i].join());
            }

            keys.push(stops.join(','));
        }

        return keys.join('_');
    }

    function getSymbolStamp(symbol) {
        var keys = [];

        if (Array.isArray(symbol)) {
            for (var i = 0; i < symbol.length; i++) {
                keys.push(getSymbolStamp(symbol[i]));
            }

            return '[ ' + keys.join(' , ') + ' ]';
        }

        for (var p in symbol) {
            if (hasOwn(symbol, p)) {
                if (!isFunction(symbol[p])) {
                    if (isGradient(symbol[p])) {
                        keys.push(p + '=' + getGradientStamp(symbol[p]));
                    } else {
                        keys.push(p + '=' + symbol[p]);
                    }
                }
            }
        }

        return keys.join(';');
    }

    function lowerSymbolOpacity(symbol, ratio) {
        function s(_symbol, _ratio) {
            var op = _symbol['opacity'];

            if (isNil(op)) {
                _symbol['opacity'] = _ratio;
            } else {
                _symbol['opacity'] *= _ratio;
            }
        }

        var lower;

        if (Array.isArray(symbol)) {
            lower = [];

            for (var i = 0; i < symbol.length; i++) {
                var d = extend({}, symbol[i]);
                s(d, ratio);
                lower.push(d);
            }
        } else {
            lower = extend({}, symbol);
            s(lower, ratio);
        }

        return lower;
    }

    function extendSymbol(symbol) {
        var sources = Array.prototype.slice.call(arguments, 1);

        if (!sources || !sources.length) {
            sources = [{}];
        }

        if (Array.isArray(symbol)) {
            var s, dest;
            var result = [];

            for (var i = 0, l = symbol.length; i < l; i++) {
                s = symbol[i];
                dest = {};

                for (var ii = 0, ll = sources.length; ii < ll; ii++) {
                    if (!Array.isArray(sources[ii])) {
                        extend(dest, s, sources[ii] ? sources[ii] : {});
                    } else if (!isNil(sources[ii][i])) {
                        extend(dest, s, sources[ii][i]);
                    } else {
                        extend(dest, s ? s : {});
                    }
                }

                result.push(dest);
            }

            return result;
        } else {
            var args = [{}, symbol];
            args.push.apply(args, sources);
            return extend.apply(this, args);
        }
    }

    function parseStyleRootPath(style) {
        if (style.symbol) {
            style = [style];
        }

        if (Array.isArray(style)) {
            return style;
        }

        var root = style['$root'];
        var iconset = style['$iconset'];
        style = style.style;

        if (root || iconset) {
            if (root && root[root.length - 1] === '/') {
                root = root.substring(0, root.length - 1);
            }

            if (iconset && iconset[iconset.length - 1] === '/') {
                iconset = iconset.substring(0, iconset.length - 1);
            }

            var replacer = function replacer(match) {
                if (match === '{$root}') {
                    return root;
                } else if (match === '{$iconset}') {
                    return iconset;
                }

                return null;
            };

            style = convertStylePath(style, replacer);
        }

        return style;
    }

    function convertStylePath(styles, replacer) {
        for (var i = 0; i < styles.length; i++) {
            var symbol = styles[i].symbol;

            if (symbol) {
                parseSymbolPath(symbol, replacer);
            }
        }
    }
    var URL_PATTERN = /(\{\$root\}|\{\$iconset\})/g;

    function parseSymbolPath(symbol, replacer) {
        for (var p in symbol) {
            if (symbol.hasOwnProperty(p) && p !== 'textName') {
                if (isString(symbol[p]) && symbol[p].length > 2) {
                    symbol[p] = symbol[p].replace(URL_PATTERN, replacer);
                } else if (isFunctionDefinition(symbol[p])) {
                    symbol[p] = parseStops(symbol[p], replacer);
                } else if (isObject(symbol[p])) {
                    parseSymbolPath(symbol[p], replacer);
                }
            }
        }
    }

    function parseStops(value, replacer) {
        var defaultValue = value['default'];

        if (isString(defaultValue)) {
            value['default'] = defaultValue.replace(URL_PATTERN, replacer);
        }

        var stops = value.stops;

        for (var i = 0; i < stops.length; i++) {
            if (!Array.isArray(stops[i])) {
                continue;
            }

            if (isString(stops[i][1])) {
                stops[i][1] = stops[i][1].replace(URL_PATTERN, replacer);
            } else if (isFunctionDefinition(stops[i][1])) {
                stops[i][1] = parseStops(stops[i][1], replacer);
            }
        }

        return value;
    }



    var index$1 = /*#__PURE__*/ Object.freeze({
        now: now,
        extend: extend,
        isNil: isNil,
        isNumber: isNumber,
        isInteger: isInteger,
        isObject: isObject,
        isString: isString,
        isFunction: isFunction,
        hasOwn: hasOwn,
        join: join,
        isEmpty: isEmpty,
        toRadian: toRadian,
        toDegree: toDegree,
        IS_NODE: IS_NODE,
        get requestAnimFrame() { return requestAnimFrame; },
        get cancelAnimFrame() { return cancelAnimFrame; },
        isSVG: isSVG,
        loadImage: loadImage,
        UID: UID,
        GUID: GUID,
        parseJSON: parseJSON,
        pushIn: pushIn,
        removeFromArray: removeFromArray,
        forEachCoord: forEachCoord,
        getValueOrDefault: getValueOrDefault,
        sign: sign,
        log2: log2,
        interpolate: interpolate,
        wrap: wrap,
        clamp: clamp,
        isArrayHasData: isArrayHasData,
        isURL: isURL,
        isCssUrl: isCssUrl,
        extractCssUrl: extractCssUrl,
        btoa: btoa,
        b64toBlob: b64toBlob,
        computeDegree: computeDegree,
        emptyImageUrl: emptyImageUrl,
        equalMapView: equalMapView,
        flash: flash,
        _defaults: _defaults,
        translateToSVGStyles: translateToSVGStyles,
        getMarkerPathBase64: getMarkerPathBase64,
        getExternalResources: getExternalResources,
        convertResourceUrl: convertResourceUrl,
        isGradient: isGradient,
        getGradientStamp: getGradientStamp,
        getSymbolStamp: getSymbolStamp,
        lowerSymbolOpacity: lowerSymbolOpacity,
        extendSymbol: extendSymbol,
        parseStyleRootPath: parseStyleRootPath,
        convertStylePath: convertStylePath
    });

    var Browser = {};

    if (!IS_NODE) {
        var ua = navigator.userAgent.toLowerCase(),
            doc = document.documentElement,
            ie = 'ActiveXObject' in window,
            webkit = ua.indexOf('webkit') !== -1,
            phantomjs = ua.indexOf('phantom') !== -1,
            android23 = ua.search('android [23]') !== -1,
            chrome = ua.indexOf('chrome') !== -1,
            gecko = ua.indexOf('gecko') !== -1 && !webkit && !window.opera && !ie,
            mobile = typeof orientation !== 'undefined' || ua.indexOf('mobile') !== -1,
            msPointer = !window.PointerEvent && window.MSPointerEvent,
            pointer = window.PointerEvent && navigator.pointerEnabled || msPointer,
            ie3d = ie && 'transition' in doc.style,
            webkit3d = 'WebKitCSSMatrix' in window && 'm11' in new window.WebKitCSSMatrix() && !android23,
            gecko3d = 'MozPerspective' in doc.style,
            opera12 = 'OTransition' in doc.style,
            any3d = (ie3d || webkit3d || gecko3d) && !opera12 && !phantomjs;
        var chromeVersion = 0;

        if (chrome) {
            chromeVersion = ua.match(/chrome\/([\d.]+)/)[1];
        }

        var touch = !phantomjs && (pointer || 'ontouchstart' in window || window.DocumentTouch && document instanceof window.DocumentTouch);
        var webgl;

        try {
            var canvas = document.createElement('canvas');
            var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
            webgl = gl && gl instanceof WebGLRenderingContext;
        } catch (err) {
            webgl = false;
        }

        var devicePixelRatio = window.devicePixelRatio || window.screen.deviceXDPI / window.screen.logicalXDPI;
        Browser = {
            ie: ie,
            ielt9: ie && !document.addEventListener,
            edge: 'msLaunchUri' in navigator && !('documentMode' in document),
            webkit: webkit,
            gecko: gecko,
            android: ua.indexOf('android') !== -1,
            android23: android23,
            chrome: chrome,
            chromeVersion: chromeVersion,
            safari: !chrome && ua.indexOf('safari') !== -1,
            phantomjs: phantomjs,
            ie3d: ie3d,
            webkit3d: webkit3d,
            gecko3d: gecko3d,
            opera12: opera12,
            any3d: any3d,
            mobile: mobile,
            mobileWebkit: mobile && webkit,
            mobileWebkit3d: mobile && webkit3d,
            mobileOpera: mobile && window.opera,
            mobileGecko: mobile && gecko,
            touch: !!touch,
            msPointer: !!msPointer,
            pointer: !!pointer,
            retina: devicePixelRatio > 1,
            devicePixelRatio: devicePixelRatio,
            language: navigator.browserLanguage ? navigator.browserLanguage : navigator.language,
            ie9: ie && document.documentMode === 9,
            ie10: ie && document.documentMode === 10,
            webgl: webgl
        };
    }

    var Browser$1 = Browser;

    function _inheritsLoose(subClass, superClass) {
        subClass.prototype = Object.create(superClass.prototype);
        subClass.prototype.constructor = subClass;
        if (typeof document !== 'undefined' && document.documentMode < 11) { _defaults(subClass, superClass); } else { subClass.__proto__ = superClass; }
    }

    function _assertThisInitialized(self) {
        if (self === void 0) {
            throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
        }

        return self;
    }

    var Position = function() {
        function Position(x, y) {
            if (!isNil(x) && !isNil(y)) {
                this.x = +x;
                this.y = +y;
            } else if (!isNil(x.x) && !isNil(x.y)) {
                this.x = +x.x;
                this.y = +x.y;
            } else if (Array.isArray(x)) {
                this.x = +x[0];
                this.y = +x[1];
            }

            if (this._isNaN()) {
                throw new Error('Position is NaN');
            }
        }

        var _proto = Position.prototype;

        _proto.set = function set(x, y) {
            this.x = x;
            this.y = y;
            return this;
        };

        _proto.abs = function abs() {
            return new this.constructor(Math.abs(this.x), Math.abs(this.y));
        };

        _proto._abs = function _abs() {
            this.x = Math.abs(this.x);
            this.y = Math.abs(this.y);
            return this;
        };

        _proto._round = function _round() {
            this.x = Math.round(this.x);
            this.y = Math.round(this.y);
            return this;
        };

        _proto.round = function round() {
            return new this.constructor(Math.round(this.x), Math.round(this.y));
        };

        _proto._ceil = function _ceil() {
            this.x = Math.ceil(this.x);
            this.y = Math.ceil(this.y);
            return this;
        };

        _proto.ceil = function ceil() {
            return new this.constructor(Math.ceil(this.x), Math.ceil(this.y));
        };

        _proto.distanceTo = function distanceTo(point) {
            var x = point.x - this.x,
                y = point.y - this.y;
            return Math.sqrt(x * x + y * y);
        };

        _proto._floor = function _floor() {
            this.x = Math.floor(this.x);
            this.y = Math.floor(this.y);
            return this;
        };

        _proto.floor = function floor() {
            return new this.constructor(Math.floor(this.x), Math.floor(this.y));
        };

        _proto.copy = function copy() {
            return new this.constructor(this.x, this.y);
        };

        _proto._add = function _add(x, y) {
            if (!isNil(x.x)) {
                this.x += x.x;
                this.y += x.y;
            } else if (!isNil(x[0])) {
                this.x += x[0];
                this.y += x[1];
            } else {
                this.x += x;
                this.y += y;
            }

            return this;
        };

        _proto.add = function add(x, y) {
            var nx, ny;

            if (!isNil(x.x)) {
                nx = this.x + x.x;
                ny = this.y + x.y;
            } else if (!isNil(x[0])) {
                nx = this.x + x[0];
                ny = this.y + x[1];
            } else {
                nx = this.x + x;
                ny = this.y + y;
            }

            return new this.constructor(nx, ny);
        };

        _proto._sub = function _sub(x, y) {
            if (!isNil(x.x)) {
                this.x -= x.x;
                this.y -= x.y;
            } else if (!isNil(x[0])) {
                this.x -= x[0];
                this.y -= x[1];
            } else {
                this.x -= x;
                this.y -= y;
            }

            return this;
        };

        _proto._substract = function _substract() {
            return this._sub.apply(this, arguments);
        };

        _proto.sub = function sub(x, y) {
            var nx, ny;

            if (!isNil(x.x)) {
                nx = this.x - x.x;
                ny = this.y - x.y;
            } else if (!isNil(x[0])) {
                nx = this.x - x[0];
                ny = this.y - x[1];
            } else {
                nx = this.x - x;
                ny = this.y - y;
            }

            return new this.constructor(nx, ny);
        };

        _proto.substract = function substract() {
            return this.sub.apply(this, arguments);
        };

        _proto.multi = function multi(ratio) {
            return new this.constructor(this.x * ratio, this.y * ratio);
        };

        _proto._multi = function _multi(ratio) {
            this.x *= ratio;
            this.y *= ratio;
            return this;
        };

        _proto.div = function div(n) {
            return this.multi(1 / n);
        };

        _proto._div = function _div(n) {
            return this._multi(1 / n);
        };

        _proto.equals = function equals(c) {
            if (!(c instanceof this.constructor)) {
                return false;
            }

            return this.x === c.x && this.y === c.y;
        };

        _proto._isNaN = function _isNaN() {
            return isNaN(this.x) || isNaN(this.y);
        };

        _proto.isZero = function isZero() {
            return this.x === 0 && this.y === 0;
        };

        _proto.toArray = function toArray() {
            return [this.x, this.y];
        };

        _proto.toFixed = function toFixed(n) {
            return new this.constructor(this.x.toFixed(n), this.y.toFixed(n));
        };

        _proto.toJSON = function toJSON() {
            return {
                x: this.x,
                y: this.y
            };
        };

        return Position;
    }();

    var Point = function(_Position) {
        _inheritsLoose(Point, _Position);

        function Point() {
            return _Position.apply(this, arguments) || this;
        }

        var _proto = Point.prototype;

        _proto.closeTo = function closeTo(p, delta) {
            if (!delta) {
                delta = 0;
            }

            return this.x >= p.x - delta && this.x <= p.x + delta && this.y >= p.y - delta && this.y <= p.y + delta;
        };

        _proto.mag = function mag() {
            return Math.sqrt(this.x * this.x + this.y * this.y);
        };

        _proto.unit = function unit() {
            return this.copy()._unit();
        };

        _proto._unit = function _unit() {
            this._div(this.mag());

            return this;
        };

        _proto.perp = function perp() {
            return this.copy()._perp();
        };

        _proto._perp = function _perp() {
            var y = this.y;
            this.y = this.x;
            this.x = -y;
            return this;
        };

        _proto.angleWith = function angleWith(b) {
            return this.angleWithSep(b.x, b.y);
        };

        _proto.angleWithSep = function angleWithSep(x, y) {
            return Math.atan2(this.x * y - this.y * x, this.x * x + this.y * y);
        };

        _proto._rotate = function _rotate(angle) {
            var cos = Math.cos(angle),
                sin = Math.sin(angle),
                x = cos * this.x - sin * this.y,
                y = sin * this.x + cos * this.y;
            this.x = x;
            this.y = y;
            return this;
        };

        _proto.rotate = function rotate(a) {
            return this.copy()._rotate(a);
        };

        return Point;
    }(Position);

    var Size = function() {
        function Size(width, height) {
            if (isNumber(width) && isNumber(height)) {
                this.width = width;
                this.height = height;
            } else if (isNumber(width['width'])) {
                this.width = width.width;
                this.height = width.height;
            } else if (Array.isArray(width)) {
                this.width = width[0];
                this.height = width[1];
            }
        }

        var _proto = Size.prototype;

        _proto.copy = function copy() {
            return new Size(this['width'], this['height']);
        };

        _proto.add = function add(x, y) {
            var w, h;

            if (x instanceof Size) {
                w = this.width + x.width;
                h = this.height + x.height;
            } else {
                w = this.width + x;
                h = this.height + y;
            }

            return new Size(w, h);
        };

        _proto.equals = function equals(size) {
            return this['width'] === size['width'] && this['height'] === size['height'];
        };

        _proto.multi = function multi(ratio) {
            return new Size(this['width'] * ratio, this['height'] * ratio);
        };

        _proto._multi = function _multi(ratio) {
            this['width'] *= ratio;
            this['height'] *= ratio;
            return this;
        };

        _proto._round = function _round() {
            this['width'] = Math.round(this['width']);
            this['height'] = Math.round(this['height']);
            return this;
        };

        _proto.toPoint = function toPoint() {
            return new Point(this['width'], this['height']);
        };

        _proto.toArray = function toArray() {
            return [this['width'], this['height']];
        };

        _proto.toJSON = function toJSON() {
            return {
                'width': this['width'],
                'height': this['height']
            };
        };

        return Size;
    }();

    function trim(str) {
        return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, '');
    }
    var specialPattern = /[\b\t\r\v\f]/igm;

    function escapeSpecialChars(str) {
        if (!isString(str)) {
            return str;
        }

        return str.replace(specialPattern, '');
    }

    function splitWords(chr) {
        return trim(chr).split(/\s+/);
    }
    var rulerCtx = typeof document !== 'undefined' ? document.createElement('canvas').getContext('2d') : null;

    function stringWidth(text, font) {
        if (stringWidth.node) {
            return stringWidth.node(text, font);
        }

        rulerCtx.font = font;
        return rulerCtx.measureText(text).width;
    }

    function stringLength(text, font, size) {
        var w = stringWidth(text, font);
        return new Size(w, size || DEFAULT_TEXT_SIZE);
    }

    function getFontHeight(font) {
        var domRuler = getDomRuler('span');

        if (font !== '_default_') {
            domRuler.style.font = font;
        }

        domRuler.innerHTML = '秦';
        var h = domRuler.clientHeight;
        removeDomNode(domRuler);
        return h;
    }

    function splitContent(content, font, wrapWidth, textWidth) {
        if (!content || content.length === 0) {
            return [{
                'text': '',
                'width': 0
            }];
        }

        var width = isNil(textWidth) ? stringWidth(content, font) : textWidth;
        var chrWidth = width / content.length,
            minChrCount = Math.floor(wrapWidth / chrWidth / 2);

        if (chrWidth >= wrapWidth || minChrCount <= 0) {
            return [{
                'text': '',
                'width': wrapWidth
            }];
        }

        if (width <= wrapWidth) return [{
            'text': content,
            'width': width
        }];
        var result = [];
        var testStr = content.substring(0, minChrCount),
            prew = chrWidth * minChrCount;

        for (var i = minChrCount, l = content.length; i < l; i++) {
            var chr = content[i];
            var w = stringWidth(testStr + chr);

            if (w >= wrapWidth) {
                result.push({
                    'text': testStr,
                    'width': prew
                });
                testStr = content.substring(i, minChrCount + i);
                i += minChrCount - 1;
                prew = chrWidth * minChrCount;
            } else {
                testStr += chr;
                prew = w;
            }

            if (i >= l - 1) {
                prew = stringWidth(testStr);
                result.push({
                    'text': testStr,
                    'width': prew
                });
            }
        }

        return result;
    }
    var contentExpRe = /\{([\w_]+)\}/g;

    function replaceVariable(str, props) {
        if (!isString(str)) {
            return str;
        }

        return str.replace(contentExpRe, function(str, key) {
            if (!props) {
                return '';
            }

            var value = props[key];

            if (isNil(value)) {
                return '';
            } else if (Array.isArray(value)) {
                return value.join();
            }

            return value;
        });
    }

    function getAlignPoint(size, horizontalAlignment, verticalAlignment) {
        var width = size['width'],
            height = size['height'];
        var alignW, alignH;

        if (horizontalAlignment === 'left') {
            alignW = -width;
        } else if (horizontalAlignment === 'right') {
            alignW = 0;
        } else {
            alignW = -width / 2;
        }

        if (verticalAlignment === 'top') {
            alignH = -height;
        } else if (verticalAlignment === 'bottom') {
            alignH = 0;
        } else {
            alignH = -height / 2;
        }

        return new Point(alignW, alignH);
    }
    var DEFAULT_FONT = 'monospace';

    function getFont(style) {
        if (style['textFont']) {
            return style['textFont'];
        } else {
            return (style['textStyle'] && style['textStyle'] !== 'normal' ? style['textStyle'] + ' ' : '') + (style['textWeight'] && style['textWeight'] !== 'normal' ? style['textWeight'] + ' ' : '') + style['textSize'] + 'px ' + (!style['textFaceName'] ? DEFAULT_FONT : style['textFaceName'][0] === '"' ? style['textFaceName'] : '"' + style['textFaceName'] + '"');
        }
    }

    function splitTextToRow(text, style) {
        var font = getFont(style),
            lineSpacing = style['textLineSpacing'] || 0,
            size = stringLength(text, font, style['textSize']),
            textWidth = size['width'],
            textHeight = size['height'],
            wrapChar = style['textWrapCharacter'],
            textRows = [];
        var wrapWidth = style['textWrapWidth'];

        if (!wrapWidth || wrapWidth > textWidth) {
            wrapWidth = textWidth;
        }

        if (!isString(text)) {
            text += '';
        }

        var actualWidth = 0;

        if (wrapChar && text.indexOf(wrapChar) >= 0) {
            var texts = text.split(wrapChar);

            for (var i = 0, l = texts.length; i < l; i++) {
                var t = texts[i];
                var tWidth = stringWidth(t, font);

                if (tWidth > wrapWidth) {
                    var contents = splitContent(t, font, wrapWidth, tWidth);

                    for (var ii = 0, ll = contents.length; ii < ll; ii++) {
                        var w = contents[ii].width;

                        if (w > actualWidth) {
                            actualWidth = w;
                        }

                        textRows.push({
                            'text': contents[ii].text,
                            'size': new Size(w, textHeight)
                        });
                    }
                } else {
                    if (tWidth > actualWidth) {
                        actualWidth = tWidth;
                    }

                    textRows.push({
                        'text': t,
                        'size': new Size(tWidth, textHeight)
                    });
                }
            }
        } else if (textWidth > wrapWidth) {
            var _contents = splitContent(text, font, wrapWidth, textWidth);

            for (var _i = 0; _i < _contents.length; _i++) {
                var _w = _contents[_i].width;

                if (_w > actualWidth) {
                    actualWidth = _w;
                }

                textRows.push({
                    'text': _contents[_i].text,
                    'size': new Size(_w, textHeight)
                });
            }
        } else {
            if (textWidth > actualWidth) {
                actualWidth = textWidth;
            }

            textRows.push({
                'text': text,
                'size': size
            });
        }

        var rowNum = textRows.length;
        var textSize = new Size(actualWidth, textHeight * rowNum + lineSpacing * (rowNum - 1));
        return {
            'total': rowNum,
            'size': textSize,
            'rows': textRows,
            'rawSize': size
        };
    }

    var strings = /*#__PURE__*/ Object.freeze({
        trim: trim,
        escapeSpecialChars: escapeSpecialChars,
        splitWords: splitWords,
        stringWidth: stringWidth,
        stringLength: stringLength,
        getFontHeight: getFontHeight,
        splitContent: splitContent,
        replaceVariable: replaceVariable,
        getAlignPoint: getAlignPoint,
        getFont: getFont,
        splitTextToRow: splitTextToRow
    });

    var first = function first(props) {
        return props[0];
    };

    var testProp = IS_NODE ? first : function(props) {
        var style = document.documentElement.style;

        for (var i = 0; i < props.length; i++) {
            if (props[i] in style) {
                return props[i];
            }
        }

        return false;
    };
    var TRANSFORM = testProp(['transform', 'WebkitTransform', 'OTransform', 'MozTransform', 'msTransform']);
    var TRANSFORMORIGIN = testProp(['transformOrigin', 'WebkitTransformOrigin', 'OTransformOrigin', 'MozTransformOrigin', 'msTransformOrigin']);
    var TRANSITION = testProp(['transition', 'WebkitTransition', 'OTransition', 'MozTransition', 'msTransition']);
    var CSSFILTER = testProp(['filter', 'WebkitFilter', 'OFilter', 'MozFilter', 'msFilter']);

    function createEl(tagName, className) {
        var el = document.createElement(tagName);

        if (className) {
            setClass(el, className);
        }

        return el;
    }

    function createElOn(tagName, style, container) {
        var el = createEl(tagName);

        if (style) {
            setStyle(el, style);
        }

        if (container) {
            container.appendChild(el);
        }

        return el;
    }

    function removeDomNode(node) {
        if (!node) {
            return this;
        }

        if (Browser$1.ielt9 || Browser$1.ie9) {
            var d = createEl('div');
            d.appendChild(node);
            d.innerHTML = '';
            d = null;
        } else if (node.parentNode) {
            node.parentNode.removeChild(node);
        }

        return this;
    }

    function addDomEvent(obj, typeArr, handler, context) {
        if (!obj || !obj.addEventListener || !typeArr || !handler) {
            return this;
        }

        var eventHandler = function eventHandler(e) {
            if (!e) {
                e = window.event;
            }

            handler.call(context || obj, e);
            return;
        };

        var types = typeArr.split(' ');

        for (var i = types.length - 1; i >= 0; i--) {
            var type = types[i];

            if (!type) {
                continue;
            }

            if (!obj['Z__' + type]) {
                obj['Z__' + type] = [];
            }

            var hit = listensDomEvent(obj, type, handler);

            if (hit >= 0) {
                removeDomEvent(obj, type, handler);
            }

            obj['Z__' + type].push({
                callback: eventHandler,
                src: handler
            });

            if (Browser$1.ie) {
                obj.addEventListener(type, eventHandler, false);
            } else {
                obj.addEventListener(type, eventHandler, {
                    capture: false,
                    passive: false
                });
            }
        }

        return this;
    }

    function removeDomEvent(obj, typeArr, handler) {
        function doRemove(type, callback) {
            if (type === 'mousewheel' && Browser$1.gecko) {
                type = 'DOMMouseScroll';
            }

            obj.removeEventListener(type, callback, false);
        }

        if (!obj || !obj.removeEventListener || !typeArr) {
            return this;
        }

        var types = typeArr.split(' ');

        for (var i = types.length - 1; i >= 0; i--) {
            var type = types[i];

            if (!type) {
                continue;
            }

            if (!handler && obj['Z__' + type]) {
                var handlers = obj['Z__' + type];

                for (var j = 0, jlen = handlers.length; j < jlen; j++) {
                    doRemove(handlers[j].callback);
                }

                delete obj['Z__' + type];
                return this;
            }

            var hit = listensDomEvent(obj, type, handler);

            if (hit < 0) {
                return this;
            }

            var hitHandler = obj['Z__' + type][hit];
            doRemove(type, hitHandler.callback);
            obj['Z__' + type].splice(hit, 1);
        }

        return this;
    }

    function listensDomEvent(obj, type, handler) {
        if (!obj || !obj['Z__' + type] || !handler) {
            return -1;
        }

        var handlers = obj['Z__' + type];

        for (var i = 0, len = handlers.length; i < len; i++) {
            if (handlers[i].src === handler) {
                return i;
            }
        }

        return -1;
    }

    function preventDefault(event) {
        if (event.preventDefault) {
            event.preventDefault();
        } else {
            event.returnValue = false;
        }

        return this;
    }

    function stopPropagation(e) {
        if (e.stopPropagation) {
            e.stopPropagation();
        } else {
            e.cancelBubble = true;
        }

        return this;
    }

    function preventSelection(dom) {
        dom.onselectstart = function() {
            return false;
        };

        dom.ondragstart = function() {
            return false;
        };

        dom.setAttribute('unselectable', 'on');
        return this;
    }

    function offsetDom(dom, offset) {
        if (!dom) {
            return null;
        }

        if (Browser$1.any3d) {
            setTransform(dom, offset);
        } else {
            dom.style.left = offset.x + 'px';
            dom.style.top = offset.y + 'px';
        }

        return offset;
    }

    function computeDomPosition(dom) {
        var style = window.getComputedStyle(dom);
        var padding = [parseInt(style['padding-left']), parseInt(style['padding-top'])];
        var rect = dom.getBoundingClientRect();
        var offsetWidth = dom.offsetWidth,
            offsetHeight = dom.offsetHeight;
        var scaleX = offsetWidth ? rect.width / offsetWidth : 1,
            scaleY = offsetHeight ? rect.height / offsetHeight : 1;
        dom.__position = [rect.left + padding[0], rect.top + padding[1], scaleX, scaleY];
        return dom.__position;
    }

    function getEventContainerPoint(ev, dom) {
        if (!ev) {
            ev = window.event;
        }

        var domPos = dom.__position;

        if (!domPos) {
            domPos = computeDomPosition(dom);
        }

        return new Point((ev.clientX - domPos[0] - dom.clientLeft) / domPos[2], (ev.clientY - domPos[1] - dom.clientTop) / domPos[3]);
    }

    function endsWith(str, suffix) {
        var l = str.length - suffix.length;
        return l >= 0 && str.indexOf(suffix, l) === l;
    }

    function setStyle(dom, strCss) {
        var cssText = dom.style.cssText;

        if (!endsWith(cssText, ';')) {
            cssText += ';';
        }

        dom.style.cssText = cssText + strCss;
        return this;
    }

    function hasClass(el, name) {
        if (el.classList !== undefined) {
            return el.classList.contains(name);
        }

        var className = getClass(el);
        return className.length > 0 && new RegExp('(^|\\s)' + name + '(\\s|$)').test(className);
    }

    function addClass(el, name) {
        if (el.classList !== undefined && !hasClass(el, name)) {
            var classes = splitWords(name);

            for (var i = 0, len = classes.length; i < len; i++) {
                el.classList.add(classes[i]);
            }
        } else {
            var className = getClass(el);
            setClass(el, (className ? className + ' ' : '') + name);
        }

        return this;
    }

    function setClass(el, name) {
        if (isNil(el.className.baseVal)) {
            el.className = name;
        } else {
            el.className.baseVal = name;
        }

        return this;
    }

    function getClass(el) {
        return isNil(el.className.baseVal) ? el.className : el.className.baseVal;
    }

    function setOpacity(el, value) {
        el.style.opacity = value;
        return this;
    }

    function setTransform(el, offset) {
        var pos = offset || new Point(0, 0);
        el.style[TRANSFORM] = Browser$1.any3d ? 'translate3d(' + pos.x + 'px,' + pos.y + 'px,0px)' : 'translate(' + pos.x + 'px,' + pos.y + 'px)';
        return this;
    }

    function setTransformMatrix(el, m) {
        var text = 'matrix(' + (isString(m) ? m : m.join()) + ')';

        if (el.style[TRANSFORM] !== text) {
            el.style[TRANSFORM] = text;
        }

        return this;
    }

    function removeTransform(el) {
        if (el.style[TRANSFORM]) {
            el.style[TRANSFORM] = '';
        }

        return this;
    }

    function isHTML(str) {
        return /<[a-z\][\s\S]*>/i.test(str);
    }

    function measureDom(parentTag, dom) {
        var ruler = getDomRuler(parentTag);

        if (isString(dom)) {
            ruler.innerHTML = dom;
        } else {
            ruler.appendChild(dom);
        }

        var result = new Size(ruler.clientWidth, ruler.clientHeight);
        removeDomNode(ruler);
        return result;
    }

    function getDomRuler(tag) {
        var span = document.createElement(tag);
        span.style.cssText = 'position:absolute;left:-10000px;top:-10000px;';
        document.body.appendChild(span);
        return span;
    }
    var on = addDomEvent;
    var off = removeDomEvent;

    var dom = /*#__PURE__*/ Object.freeze({
        TRANSFORM: TRANSFORM,
        TRANSFORMORIGIN: TRANSFORMORIGIN,
        TRANSITION: TRANSITION,
        CSSFILTER: CSSFILTER,
        createEl: createEl,
        createElOn: createElOn,
        removeDomNode: removeDomNode,
        addDomEvent: addDomEvent,
        removeDomEvent: removeDomEvent,
        listensDomEvent: listensDomEvent,
        preventDefault: preventDefault,
        stopPropagation: stopPropagation,
        preventSelection: preventSelection,
        offsetDom: offsetDom,
        computeDomPosition: computeDomPosition,
        getEventContainerPoint: getEventContainerPoint,
        setStyle: setStyle,
        hasClass: hasClass,
        addClass: addClass,
        setClass: setClass,
        getClass: getClass,
        setOpacity: setOpacity,
        setTransform: setTransform,
        setTransformMatrix: setTransformMatrix,
        removeTransform: removeTransform,
        isHTML: isHTML,
        measureDom: measureDom,
        getDomRuler: getDomRuler,
        on: on,
        off: off
    });

    var Ajax = {
        jsonp: function jsonp(url, callback) {
            var name = '_maptalks_jsonp_' + UID();
            if (url.match(/\?/)) url += '&callback=' + name;
            else url += '?callback=' + name;
            var script = document.createElement('script');
            script.type = 'text/javascript';
            script.src = url;

            window[name] = function(data) {
                callback(null, data);
                document.getElementsByTagName('head')[0].removeChild(script);
                script = null;
                delete window[name];
            };

            document.getElementsByTagName('head')[0].appendChild(script);
            return this;
        },
        get: function get(url, options, cb) {
            if (isFunction(options)) {
                var t = cb;
                cb = options;
                options = t;
            }

            if (IS_NODE && Ajax.get.node) {
                return Ajax.get.node(url, cb, options);
            }

            var client = Ajax._getClient(cb);

            client.open('GET', url, true);

            if (options) {
                for (var k in options.headers) {
                    client.setRequestHeader(k, options.headers[k]);
                }

                client.withCredentials = options.credentials === 'include';

                if (options['responseType']) {
                    client.responseType = options['responseType'];
                }
            }

            client.send(null);
            return client;
        },
        post: function post(url, options, cb) {
            var postData;

            if (!isString(url)) {
                var t = cb;
                postData = options;
                options = url;
                url = options.url;
                cb = t;
            } else {
                if (isFunction(options)) {
                    var _t = cb;
                    cb = options;
                    options = _t;
                }

                options = options || {};
                postData = options.postData;
            }

            if (IS_NODE && Ajax.post.node) {
                options.url = url;
                return Ajax.post.node(options, postData, cb);
            }

            var client = Ajax._getClient(cb);

            client.open('POST', options.url, true);

            if (!options.headers) {
                options.headers = {};
            }

            if (!options.headers['Content-Type']) {
                options.headers['Content-Type'] = 'application/x-www-form-urlencoded';
            }

            if ('setRequestHeader' in client) {
                for (var p in options.headers) {
                    if (options.headers.hasOwnProperty(p)) {
                        client.setRequestHeader(p, options.headers[p]);
                    }
                }
            }

            if (!isString(postData)) {
                postData = JSON.stringify(postData);
            }

            client.send(postData);
            return client;
        },
        _wrapCallback: function _wrapCallback(client, cb) {
            return function() {
                if (client.readyState === 4) {
                    if (client.status === 200) {
                        if (client.responseType === 'arraybuffer') {
                            var response = client.response;

                            if (response.byteLength === 0) {
                                cb(new Error('http status 200 returned without content.'));
                            } else {
                                cb(null, {
                                    data: client.response,
                                    cacheControl: client.getResponseHeader('Cache-Control'),
                                    expires: client.getResponseHeader('Expires'),
                                    contentType: client.getResponseHeader('Content-Type')
                                });
                            }
                        } else {
                            cb(null, client.responseText);
                        }
                    } else {
                        cb(new Error(client.statusText + ',' + client.status));
                    }
                }
            };
        },
        _getClient: function _getClient(cb) {
            var client;

            try {
                client = new XMLHttpRequest();
            } catch (e) {
                try {
                    client = new ActiveXObject('Msxml2.XMLHTTP');
                } catch (e) {
                    try {
                        client = new ActiveXObject('Microsoft.XMLHTTP');
                    } catch (e) {}
                }
            }

            client.onreadystatechange = Ajax._wrapCallback(client, cb);
            return client;
        },
        getArrayBuffer: function getArrayBuffer(url, options, cb) {
            if (isFunction(options)) {
                var t = cb;
                cb = options;
                options = t;
            }

            if (!options) {
                options = {};
            }

            options['responseType'] = 'arraybuffer';
            return Ajax.get(url, options, cb);
        },
        getImage: function getImage(img, url, options) {
            return Ajax.getArrayBuffer(url, options, function(err, imgData) {
                if (err) {
                    if (img.onerror) {
                        img.onerror(err);
                    }
                } else if (imgData) {
                    var URL = window.URL || window.webkitURL;
                    var onload = img.onload;

                    img.onload = function() {
                        if (onload) {
                            onload();
                        }

                        URL.revokeObjectURL(img.src);
                    };

                    var blob = new Blob([new Uint8Array(imgData.data)], {
                        type: imgData.contentType
                    });
                    img.cacheControl = imgData.cacheControl;
                    img.expires = imgData.expires;
                    img.src = imgData.data.byteLength ? URL.createObjectURL(blob) : emptyImageUrl;
                }
            });
        }
    };

    Ajax.getJSON = function(url, options, cb) {
        if (isFunction(options)) {
            var t = cb;
            cb = options;
            options = t;
        }

        var callback = function callback(err, resp) {
            var data = resp ? parseJSON(resp) : null;
            cb(err, data);
        };

        if (options && options['jsonp']) {
            return Ajax.jsonp(url, callback);
        }

        return Ajax.get(url, options, callback);
    };

    var DEFAULT_STROKE_COLOR = '#000';
    var DEFAULT_FILL_COLOR = 'rgba(255,255,255,0)';
    var DEFAULT_TEXT_COLOR = '#000';
    var hitTesting = false;
    var TEMP_CANVAS = null;
    var RADIAN = Math.PI / 180;
    var textOffsetY = 1;
    var Canvas = {
        setHitTesting: function setHitTesting(testing) {
            hitTesting = testing;
        },
        createCanvas: function createCanvas(width, height, canvasClass) {
            var canvas;

            if (!IS_NODE) {
                canvas = createEl('canvas');
                canvas.width = width;
                canvas.height = height;
            } else {
                canvas = new canvasClass(width, height);
            }

            return canvas;
        },
        prepareCanvasFont: function prepareCanvasFont(ctx, style) {
            ctx.textBaseline = 'top';
            ctx.font = getFont(style);
            var fill = style['textFill'];

            if (!fill) {
                fill = DEFAULT_TEXT_COLOR;
            }

            ctx.fillStyle = Canvas.getRgba(fill, style['textOpacity']);
        },
        prepareCanvas: function prepareCanvas(ctx, style, resources, testing) {
            if (!style) {
                return;
            }

            var strokeWidth = style['lineWidth'];

            if (!isNil(strokeWidth) && ctx.lineWidth !== strokeWidth) {
                ctx.lineWidth = strokeWidth;
            }

            var strokePattern = style['linePatternFile'];
            var strokeColor = style['lineColor'] || DEFAULT_STROKE_COLOR;

            if (testing) {
                ctx.strokeStyle = '#000';
            } else if (strokePattern && resources) {
                var patternOffset;

                if (style['linePatternDx'] || style['linePatternDy']) {
                    patternOffset = [style['linePatternDx'], style['linePatternDy']];
                }

                Canvas._setStrokePattern(ctx, strokePattern, strokeWidth, patternOffset, resources);

                style['lineDasharray'] = [];
            } else if (isGradient(strokeColor)) {
                if (style['lineGradientExtent']) {
                    ctx.strokeStyle = Canvas._createGradient(ctx, strokeColor, style['lineGradientExtent']);
                } else {
                    ctx.strokeStyle = DEFAULT_STROKE_COLOR;
                }
            } else {
                ctx.strokeStyle = strokeColor;
            }

            if (style['lineJoin']) {
                ctx.lineJoin = style['lineJoin'];
            }

            if (style['lineCap']) {
                ctx.lineCap = style['lineCap'];
            }

            if (ctx.setLineDash && isArrayHasData(style['lineDasharray'])) {
                ctx.setLineDash(style['lineDasharray']);
            }

            var polygonPattern = style['polygonPatternFile'];
            var fill = style['polygonFill'] || DEFAULT_FILL_COLOR;

            if (testing) {
                ctx.fillStyle = '#000';
            } else if (polygonPattern && resources) {
                var fillImgUrl = extractImageUrl(polygonPattern);
                var fillTexture = resources.getImage([fillImgUrl, null, null]);

                if (!fillTexture) {
                    fillTexture = resources.getImage([fillImgUrl + '-texture', null, strokeWidth]);
                }

                if (isSVG(fillImgUrl) && fillTexture instanceof Image && (Browser$1.edge || Browser$1.ie)) {
                    var w = fillTexture.width || 20,
                        h = fillTexture.height || 20;
                    var canvas = Canvas.createCanvas(w, h);
                    Canvas.image(canvas.getContext('2d'), fillTexture, 0, 0, w, h);
                    fillTexture = canvas;
                }

                if (!fillTexture) {
                    if (typeof console !== 'undefined') {
                        console.warn('img not found for', fillImgUrl);
                    }
                } else {
                    ctx.fillStyle = ctx.createPattern(fillTexture, 'repeat');

                    if (style['polygonPatternDx'] || style['polygonPatternDy']) {
                        ctx.fillStyle['polygonPatternOffset'] = [style['polygonPatternDx'], style['polygonPatternDy']];
                    }
                }
            } else if (isGradient(fill)) {
                if (style['polygonGradientExtent']) {
                    ctx.fillStyle = Canvas._createGradient(ctx, fill, style['polygonGradientExtent']);
                } else {
                    ctx.fillStyle = 'rgba(255,255,255,0)';
                }
            } else {
                ctx.fillStyle = fill;
            }
        },
        _createGradient: function _createGradient(ctx, g, extent) {
            var gradient = null,
                places = g['places'];
            var min = extent.getMin(),
                max = extent.getMax(),
                width = extent.getWidth(),
                height = extent.getHeight();

            if (!g['type'] || g['type'] === 'linear') {
                if (!places) {
                    places = [min.x, min.y, max.x, min.y];
                } else {
                    if (places.length !== 4) {
                        throw new Error('A linear gradient\'s places should have 4 numbers.');
                    }

                    places = [min.x + places[0] * width, min.y + places[1] * height, min.x + places[2] * width, min.y + places[3] * height];
                }

                gradient = ctx.createLinearGradient.apply(ctx, places);
            } else if (g['type'] === 'radial') {
                if (!places) {
                    var c = extent.getCenter()._round();

                    places = [c.x, c.y, Math.abs(c.x - min.x), c.x, c.y, 0];
                } else {
                    if (places.length !== 6) {
                        throw new Error('A radial gradient\'s places should have 6 numbers.');
                    }

                    places = [min.x + places[0] * width, min.y + places[1] * height, width * places[2], min.x + places[3] * width, min.y + places[4] * height, width * places[5]];
                }

                gradient = ctx.createRadialGradient.apply(ctx, places);
            }

            g['colorStops'].forEach(function(stop) {
                gradient.addColorStop.apply(gradient, stop);
            });
            return gradient;
        },
        _setStrokePattern: function _setStrokePattern(ctx, strokePattern, strokeWidth, linePatternOffset, resources) {
            var imgUrl = extractImageUrl(strokePattern);
            var imageTexture;

            if (IS_NODE) {
                imageTexture = resources.getImage([imgUrl, null, strokeWidth]);
            } else {
                var key = imgUrl + '-texture-' + strokeWidth;
                imageTexture = resources.getImage(key);

                if (!imageTexture) {
                    var imageRes = resources.getImage([imgUrl, null, null]);

                    if (imageRes) {
                        var w;

                        if (!imageRes.width || !imageRes.height) {
                            w = strokeWidth;
                        } else {
                            w = Math.round(imageRes.width * strokeWidth / imageRes.height);
                        }

                        var patternCanvas = Canvas.createCanvas(w, strokeWidth, ctx.canvas.constructor);
                        Canvas.image(patternCanvas.getContext('2d'), imageRes, 0, 0, w, strokeWidth);
                        resources.addResource([key, null, strokeWidth], patternCanvas);
                        imageTexture = patternCanvas;
                    }
                }
            }

            if (imageTexture) {
                ctx.strokeStyle = ctx.createPattern(imageTexture, 'repeat');
                ctx.strokeStyle['linePatternOffset'] = linePatternOffset;
            } else if (typeof console !== 'undefined') {
                console.warn('img not found for', imgUrl);
            }
        },
        clearRect: function clearRect(ctx, x1, y1, x2, y2) {
            ctx.canvas._drawn = false;
            ctx.clearRect(x1, y1, x2, y2);
        },
        fillCanvas: function fillCanvas(ctx, fillOpacity, x, y) {
            if (hitTesting) {
                fillOpacity = 1;
            }

            ctx.canvas._drawn = true;

            if (fillOpacity === 0) {
                return;
            }

            var isPattern = Canvas._isPattern(ctx.fillStyle);

            var offset = ctx.fillStyle && ctx.fillStyle['polygonPatternOffset'];
            var dx = offset ? offset[0] : 0,
                dy = offset ? offset[1] : 0;

            if (isNil(fillOpacity)) {
                fillOpacity = 1;
            }

            var alpha;

            if (fillOpacity < 1) {
                alpha = ctx.globalAlpha;
                ctx.globalAlpha *= fillOpacity;
            }

            if (isPattern) {
                x = x || 0;
                y = y || 0;
                ctx.translate(x + dx, y + dy);
            }

            ctx.fill();

            if (isPattern) {
                ctx.translate(-x - dx, -y - dy);
            }

            if (fillOpacity < 1) {
                ctx.globalAlpha = alpha;
            }
        },
        getRgba: function getRgba(color, op) {
            if (isNil(op)) {
                op = 1;
            }

            if (color[0] !== '#') {
                return color;
            }

            var r, g, b;

            if (color.length === 7) {
                r = parseInt(color.substring(1, 3), 16);
                g = parseInt(color.substring(3, 5), 16);
                b = parseInt(color.substring(5, 7), 16);
            } else {
                r = parseInt(color.substring(1, 2), 16) * 17;
                g = parseInt(color.substring(2, 3), 16) * 17;
                b = parseInt(color.substring(3, 4), 16) * 17;
            }

            return 'rgba(' + r + ',' + g + ',' + b + ',' + op + ')';
        },
        image: function image(ctx, img, x, y, width, height) {
            ctx.canvas._drawn = true;

            try {
                if (isNumber(width) && isNumber(height)) {
                    ctx.drawImage(img, x, y, width, height);
                } else {
                    ctx.drawImage(img, x, y);
                }
            } catch (error) {
                if (console) {
                    console.warn('error when drawing image on canvas:', error);
                    console.warn(img);
                }
            }
        },
        text: function text(ctx, _text, pt, style, textDesc) {
            Canvas._textOnMultiRow(ctx, textDesc['rows'], style, pt, textDesc['size'], textDesc['rawSize']);
        },
        _textOnMultiRow: function _textOnMultiRow(ctx, texts, style, point, splitTextSize, textSize) {
            var ptAlign = getAlignPoint(splitTextSize, style['textHorizontalAlignment'], style['textVerticalAlignment']),
                lineHeight = textSize['height'] + style['textLineSpacing'],
                basePoint = point.add(0, ptAlign.y),
                maxHeight = style['textMaxHeight'];
            var text,
                rowAlign,
                height = 0;

            for (var i = 0, len = texts.length; i < len; i++) {
                text = texts[i]['text'];
                rowAlign = getAlignPoint(texts[i]['size'], style['textHorizontalAlignment'], style['textVerticalAlignment']);

                Canvas._textOnLine(ctx, text, basePoint.add(rowAlign.x, i * lineHeight), style['textHaloRadius'], style['textHaloFill'], style['textHaloOpacity']);

                if (maxHeight > 0) {
                    height += lineHeight;

                    if (height + textSize['height'] >= maxHeight) {
                        break;
                    }
                }
            }
        },
        _textOnLine: function _textOnLine(ctx, text, pt, textHaloRadius, textHaloFill, textHaloAlpha) {
            if (hitTesting) {
                textHaloAlpha = 1;
            }

            var drawHalo = textHaloAlpha !== 0 && textHaloRadius !== 0;
            ctx.textBaseline = 'top';
            var gco, fill;
            var shadowBlur = ctx.shadowBlur,
                shadowOffsetX = ctx.shadowOffsetX,
                shadowOffsetY = ctx.shadowOffsetY;

            if (drawHalo) {
                var alpha = ctx.globalAlpha;
                ctx.globalAlpha *= textHaloAlpha;
                ctx.miterLimit = 2;
                ctx.lineJoin = 'round';
                ctx.lineCap = 'round';
                ctx.lineWidth = textHaloRadius * 2;
                ctx.strokeStyle = textHaloFill;
                ctx.strokeText(text, pt.x, pt.y + textOffsetY);
                ctx.miterLimit = 10;
                ctx.globalAlpha = alpha;
                gco = ctx.globalCompositeOperation;
                ctx.globalCompositeOperation = 'destination-out';
                fill = ctx.fillStyle;
                ctx.fillStyle = '#000';
            }

            if (shadowBlur && drawHalo) {
                ctx.shadowBlur = ctx.shadowOffsetX = ctx.shadowOffsetY = 0;
            }

            Canvas.fillText(ctx, text, pt);

            if (gco) {
                ctx.globalCompositeOperation = gco;
                Canvas.fillText(ctx, text, pt, fill);

                if (shadowBlur) {
                    ctx.shadowBlur = shadowBlur;
                    ctx.shadowOffsetX = shadowOffsetX;
                    ctx.shadowOffsetY = shadowOffsetY;
                }
            }
        },
        fillText: function fillText(ctx, text, pt, rgba) {
            ctx.canvas._drawn = true;

            if (rgba) {
                ctx.fillStyle = rgba;
            }

            ctx.fillText(text, pt.x, pt.y + textOffsetY);
        },
        _stroke: function _stroke(ctx, strokeOpacity, x, y) {
            if (hitTesting) {
                strokeOpacity = 1;
            }

            ctx.canvas._drawn = true;

            if (strokeOpacity === 0) {
                return;
            }

            var offset = ctx.strokeStyle && ctx.strokeStyle['linePatternOffset'];
            var dx = offset ? offset[0] : 0,
                dy = offset ? offset[1] : 0;
            var isPattern = Canvas._isPattern(ctx.strokeStyle) && (!isNil(x) && !isNil(y) || !isNil(dx) && !isNil(dy));

            if (isNil(strokeOpacity)) {
                strokeOpacity = 1;
            }

            var alpha;

            if (strokeOpacity < 1) {
                alpha = ctx.globalAlpha;
                ctx.globalAlpha *= strokeOpacity;
            }

            if (isPattern) {
                x = x || 0;
                y = y || 0;
                ctx.translate(x + dx, y + dy);
            }

            ctx.stroke();

            if (isPattern) {
                ctx.translate(-x - dx, -y - dy);
            }

            if (strokeOpacity < 1) {
                ctx.globalAlpha = alpha;
            }
        },
        _path: function _path(ctx, points, lineDashArray, lineOpacity, ignoreStrokePattern) {
            if (!isArrayHasData(points)) {
                return;
            }

            function fillWithPattern(p1, p2) {
                var degree = computeDegree(p1.x, p1.y, p2.x, p2.y);
                ctx.save();
                var cosd = Math.cos(degree);

                if (Math.abs(cosd) < 1E-7) {
                    ctx.translate(p1.x - ctx.lineWidth / 2, p1.y);
                } else {
                    ctx.translate(p1.x, p1.y - ctx.lineWidth / 2 / cosd);
                }

                ctx.rotate(degree);

                Canvas._stroke(ctx, lineOpacity);

                ctx.restore();
            }

            var isDashed = isArrayHasData(lineDashArray);
            var isPatternLine = ignoreStrokePattern === true ? false : Canvas._isPattern(ctx.strokeStyle);
            var point, prePoint, nextPoint;

            for (var i = 0, len = points.length; i < len; i++) {
                point = points[i];

                if (!isDashed || ctx.setLineDash) {
                    ctx.lineTo(point.x, point.y);

                    if (isPatternLine && i > 0) {
                        prePoint = points[i - 1];
                        fillWithPattern(prePoint, point);
                        ctx.beginPath();
                        ctx.moveTo(point.x, point.y);
                    }
                } else if (isDashed) {
                    if (i === len - 1) {
                        break;
                    }

                    nextPoint = points[i + 1];
                    drawDashLine(ctx, point, nextPoint, lineDashArray, isPatternLine);
                }
            }
        },
        path: function path(ctx, points, lineOpacity, fillOpacity, lineDashArray) {
            if (!isArrayHasData(points)) {
                return;
            }

            ctx.beginPath();
            ctx.moveTo(points[0].x, points[0].y);

            Canvas._path(ctx, points, lineDashArray, lineOpacity);

            Canvas._stroke(ctx, lineOpacity);
        },
        _multiClip: function _multiClip(ctx, points) {
            if (!points || points.length === 0) return;
            points = points[0];

            for (var i = 0, len = points.length; i < len; i++) {
                var point = points[i];
                var x = point.x,
                    y = point.y;

                if (i === 0) {
                    ctx.moveTo(x, y);
                } else {
                    ctx.lineTo(x, y);
                }

                if (i === len - 1) {
                    x = points[0].x;
                    y = points[0].y;
                    ctx.lineTo(x, y);
                }
            }
        },
        polygon: function polygon(ctx, points, lineOpacity, fillOpacity, lineDashArray, smoothness) {
            if (ctx.isMultiClip) {
                Canvas._multiClip(ctx, points);

                return;
            }

            if (!isArrayHasData(points)) {
                return;
            }

            var isPatternLine = Canvas._isPattern(ctx.strokeStyle),
                fillFirst = isArrayHasData(lineDashArray) && !ctx.setLineDash || isPatternLine && !smoothness;

            if (!isArrayHasData(points[0])) {
                points = [points];
            }

            var savedCtx = ctx;

            if (points.length > 1 && !IS_NODE) {
                if (!TEMP_CANVAS) {
                    TEMP_CANVAS = Canvas.createCanvas(1, 1);
                }

                ctx.canvas._drawn = false;
                TEMP_CANVAS.width = ctx.canvas.width;
                TEMP_CANVAS.height = ctx.canvas.height;
                ctx = TEMP_CANVAS.getContext('2d');
                copyProperties(ctx, savedCtx);
            }

            var op, i, len;

            if (fillFirst) {
                ctx.save();

                for (i = 0, len = points.length; i < len; i++) {
                    if (!isArrayHasData(points[i])) {
                        continue;
                    }

                    Canvas._ring(ctx, points[i], null, 0, true);

                    op = fillOpacity;

                    if (i > 0) {
                        ctx.globalCompositeOperation = 'destination-out';
                        op = 1;
                    }

                    Canvas.fillCanvas(ctx, op, points[i][0].x, points[i][0].y);

                    if (i > 0) {
                        ctx.globalCompositeOperation = 'source-over';
                    } else if (len > 1) {
                        ctx.fillStyle = '#fff';
                    }

                    Canvas._stroke(ctx, 0);
                }

                ctx.restore();
            }

            for (i = 0, len = points.length; i < len; i++) {
                if (!isArrayHasData(points[i])) {
                    continue;
                }

                if (smoothness) {
                    Canvas.paintSmoothLine(ctx, points[i], lineOpacity, smoothness, true);
                    ctx.closePath();
                } else {
                    Canvas._ring(ctx, points[i], lineDashArray, lineOpacity);
                }

                if (!fillFirst) {
                    op = fillOpacity;

                    if (i > 0) {
                        ctx.globalCompositeOperation = 'destination-out';
                        op = 1;
                    }

                    Canvas.fillCanvas(ctx, op, points[i][0].x, points[i][0].y);

                    if (i > 0) {
                        ctx.globalCompositeOperation = 'source-over';
                    } else if (len > 1) {
                        ctx.fillStyle = '#fff';
                    }
                }

                Canvas._stroke(ctx, lineOpacity);
            }

            if (points.length > 1 && !IS_NODE) {
                savedCtx.drawImage(TEMP_CANVAS, 0, 0);
                savedCtx.canvas._drawn = ctx.canvas._drawn;
                copyProperties(savedCtx, ctx);
            }
        },
        _ring: function _ring(ctx, ring, lineDashArray, lineOpacity, ignorePattern) {
            var isPattern = Canvas._isPattern(ctx.strokeStyle);

            if (!ignorePattern && isPattern && !ring[0].equals(ring[ring.length - 1])) {
                ring = ring.concat([ring[0]]);
            }

            ctx.beginPath();
            ctx.moveTo(ring[0].x, ring[0].y);

            Canvas._path(ctx, ring, lineDashArray, lineOpacity, ignorePattern);

            if (!isPattern) {
                ctx.closePath();
            }
        },
        paintSmoothLine: function paintSmoothLine(ctx, points, lineOpacity, smoothValue, close, tailIdx, tailRatio) {
            if (!points) {
                return;
            }

            if (points.length <= 2 || !smoothValue) {
                Canvas.path(ctx, points, lineOpacity);
                return;
            }

            function interpolate$$1(t0, t1, x1, y1, bx1, by1, bx2, by2, x2, y2) {
                var u0 = 1.0 - t0;
                var u1 = 1.0 - t1;
                var qxa = x1 * u0 * u0 + bx1 * 2 * t0 * u0 + bx2 * t0 * t0;
                var qxb = x1 * u1 * u1 + bx1 * 2 * t1 * u1 + bx2 * t1 * t1;
                var qxc = bx1 * u0 * u0 + bx2 * 2 * t0 * u0 + x2 * t0 * t0;
                var qxd = bx1 * u1 * u1 + bx2 * 2 * t1 * u1 + x2 * t1 * t1;
                var qya = y1 * u0 * u0 + by1 * 2 * t0 * u0 + by2 * t0 * t0;
                var qyb = y1 * u1 * u1 + by1 * 2 * t1 * u1 + by2 * t1 * t1;
                var qyc = by1 * u0 * u0 + by2 * 2 * t0 * u0 + y2 * t0 * t0;
                var qyd = by1 * u1 * u1 + by2 * 2 * t1 * u1 + y2 * t1 * t1;
                var xb = qxa * u1 + qxc * t1;
                var xc = qxb * u0 + qxd * t0;
                var xd = qxb * u1 + qxd * t1;
                var yb = qya * u1 + qyc * t1;
                var yc = qyb * u0 + qyd * t0;
                var yd = qyb * u1 + qyd * t1;
                return [xb, yb, xc, yc, xd, yd];
            }

            function getCubicControlPoints(x0, y0, x1, y1, x2, y2, x3, y3, smoothValue, t) {
                var xc1 = (x0 + x1) / 2.0,
                    yc1 = (y0 + y1) / 2.0;
                var xc2 = (x1 + x2) / 2.0,
                    yc2 = (y1 + y2) / 2.0;
                var xc3 = (x2 + x3) / 2.0,
                    yc3 = (y2 + y3) / 2.0;
                var len1 = Math.sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
                var len2 = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
                var len3 = Math.sqrt((x3 - x2) * (x3 - x2) + (y3 - y2) * (y3 - y2));
                var k1 = len1 / (len1 + len2);
                var k2 = len2 / (len2 + len3);
                var xm1 = xc1 + (xc2 - xc1) * k1,
                    ym1 = yc1 + (yc2 - yc1) * k1;
                var xm2 = xc2 + (xc3 - xc2) * k2,
                    ym2 = yc2 + (yc3 - yc2) * k2;
                var ctrl1X = xm1 + (xc2 - xm1) * smoothValue + x1 - xm1,
                    ctrl1Y = ym1 + (yc2 - ym1) * smoothValue + y1 - ym1,
                    ctrl2X = xm2 + (xc2 - xm2) * smoothValue + x2 - xm2,
                    ctrl2Y = ym2 + (yc2 - ym2) * smoothValue + y2 - ym2;
                var ctrlPoints = [ctrl1X, ctrl1Y, ctrl2X, ctrl2Y];

                if (t < 1) {
                    return interpolate$$1(0, t, x1, y1, ctrl1X, ctrl1Y, ctrl2X, ctrl2Y, x2, y2);
                } else {
                    return ctrlPoints;
                }
            }

            var count = points.length;
            var l = close ? count : count - 1;
            ctx.beginPath();
            ctx.moveTo(points[0].x, points[0].y);
            if (tailRatio !== undefined) l -= Math.max(l - tailIdx - 1, 0);
            var preCtrlPoints;

            for (var i = 0; i < l; i++) {
                var x1 = points[i].x,
                    y1 = points[i].y;
                var x0 = void 0,
                    y0 = void 0,
                    x2 = void 0,
                    y2 = void 0,
                    x3 = void 0,
                    y3 = void 0;

                if (i - 1 < 0) {
                    if (!close) {
                        x0 = points[i + 1].x;
                        y0 = points[i + 1].y;
                    } else {
                        x0 = points[l - 1].x;
                        y0 = points[l - 1].y;
                    }
                } else {
                    x0 = points[i - 1].x;
                    y0 = points[i - 1].y;
                }

                if (i + 1 < count) {
                    x2 = points[i + 1].x;
                    y2 = points[i + 1].y;
                } else {
                    x2 = points[i + 1 - count].x;
                    y2 = points[i + 1 - count].y;
                }

                if (i + 2 < count) {
                    x3 = points[i + 2].x;
                    y3 = points[i + 2].y;
                } else if (!close) {
                    x3 = points[i].x;
                    y3 = points[i].y;
                } else {
                    x3 = points[i + 2 - count].x;
                    y3 = points[i + 2 - count].y;
                }

                var ctrlPoints = getCubicControlPoints(x0, y0, x1, y1, x2, y2, x3, y3, smoothValue, i === l - 1 ? tailRatio : 1);

                if (i === l - 1 && tailRatio >= 0 && tailRatio < 1) {
                    ctx.bezierCurveTo(ctrlPoints[0], ctrlPoints[1], ctrlPoints[2], ctrlPoints[3], ctrlPoints[4], ctrlPoints[5]);
                    points.splice(l - 1, count - (l - 1) - 1);
                    var lastPoint = new Point(ctrlPoints[4], ctrlPoints[5]);
                    lastPoint.prevCtrlPoint = new Point(ctrlPoints[2], ctrlPoints[3]);
                    points.push(lastPoint);
                    count = points.length;
                } else {
                    ctx.bezierCurveTo(ctrlPoints[0], ctrlPoints[1], ctrlPoints[2], ctrlPoints[3], x2, y2);
                }

                points[i].nextCtrlPoint = ctrlPoints.slice(0, 2);
                points[i].prevCtrlPoint = preCtrlPoints ? preCtrlPoints.slice(2) : null;
                preCtrlPoints = ctrlPoints;
            }

            if (!close && points[1].prevCtrlPoint) {
                points[0].nextCtrlPoint = points[1].prevCtrlPoint;
                delete points[0].prevCtrlPoint;
            }

            if (!points[count - 1].prevCtrlPoint) {
                points[count - 1].prevCtrlPoint = points[count - 2].nextCtrlPoint;
            }

            Canvas._stroke(ctx, lineOpacity);
        },
        _arcBetween: function _arcBetween(ctx, p1, p2, degree) {
            var a = degree,
                dist = p1.distanceTo(p2),
                r = dist / 2 / Math.sin(a / 2);
            var p1p2 = Math.asin((p2.y - p1.y) / dist);

            if (p1.x > p2.x) {
                p1p2 = Math.PI - p1p2;
            }

            var cp2 = 90 * RADIAN - a / 2,
                da = p1p2 - cp2;
            var dx = Math.cos(da) * r,
                dy = Math.sin(da) * r,
                cx = p1.x + dx,
                cy = p1.y + dy;
            var startAngle = Math.asin((p2.y - cy) / r);

            if (cx > p2.x) {
                startAngle = Math.PI - startAngle;
            }

            var endAngle = startAngle + a;
            ctx.beginPath();
            ctx.arc(cx, cy, r, startAngle, endAngle);
            return [cx, cy];
        },
        _lineTo: function _lineTo(ctx, p) {
            ctx.lineTo(p.x, p.y);
        },
        bezierCurveAndFill: function bezierCurveAndFill(ctx, points, lineOpacity, fillOpacity) {
            ctx.beginPath();
            var start = points[0];
            ctx.moveTo(start.x, start.y);
            var args = [ctx];
            args.push.apply(args, points.splice(1));

            Canvas._bezierCurveTo.apply(Canvas, args);

            Canvas.fillCanvas(ctx, fillOpacity);

            Canvas._stroke(ctx, lineOpacity);
        },
        _bezierCurveTo: function _bezierCurveTo(ctx, p1, p2, p3) {
            ctx.bezierCurveTo(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y);
        },
        ellipse: function ellipse(ctx, pt, width, heightTop, heightBottom, lineOpacity, fillOpacity) {
            function bezierEllipse(x, y, a, b, b1) {
                var k = 0.5522848,
                    ox = a * k,
                    oy = b * k,
                    oy1 = b1 * k;
                ctx.moveTo(x - a, y);
                ctx.bezierCurveTo(x - a, y - oy, x - ox, y - b, x, y - b);
                ctx.bezierCurveTo(x + ox, y - b, x + a, y - oy, x + a, y);
                ctx.bezierCurveTo(x + a, y + oy1, x + ox, y + b1, x, y + b1);
                ctx.bezierCurveTo(x - ox, y + b1, x - a, y + oy1, x - a, y);
                ctx.closePath();
            }

            ctx.beginPath();

            if (width === heightTop && width === heightBottom) {
                ctx.arc(pt.x, pt.y, width, 0, 2 * Math.PI);
            } else if (ctx.ellipse) {
                if (heightTop !== heightBottom) {
                    ctx.ellipse(pt.x, pt.y, width, heightTop, 0, RADIAN * 180, RADIAN * 360, false);
                    ctx.ellipse(pt.x, pt.y, width, heightBottom, 0, 0, RADIAN * 180, false);
                } else {
                    ctx.ellipse(pt.x, pt.y, width, heightTop, 0, 0, RADIAN * 360, false);
                }
            } else {
                bezierEllipse(pt.x, pt.y, width, heightTop, heightBottom);
            }

            Canvas.fillCanvas(ctx, fillOpacity, pt.x - width, pt.y - heightTop);

            Canvas._stroke(ctx, lineOpacity, pt.x - width, pt.y - heightTop);
        },
        rectangle: function rectangle(ctx, pt, size, lineOpacity, fillOpacity) {
            var x = pt.x,
                y = pt.y;
            ctx.beginPath();
            ctx.rect(x, y, size['width'], size['height']);
            Canvas.fillCanvas(ctx, fillOpacity, x, y);

            Canvas._stroke(ctx, lineOpacity, x, y);
        },
        sector: function sector(ctx, pt, size, angles, lineOpacity, fillOpacity) {
            var rad = RADIAN;
            var startAngle = angles[0],
                endAngle = angles[1];

            function sector(ctx, x, y, radius, startAngle, endAngle) {
                var sDeg = rad * -endAngle;
                var eDeg = rad * -startAngle;
                ctx.beginPath();
                ctx.moveTo(x, y);
                ctx.arc(x, y, radius, sDeg, eDeg);
                ctx.lineTo(x, y);
                Canvas.fillCanvas(ctx, fillOpacity, x - radius, y - radius);

                Canvas._stroke(ctx, lineOpacity, x - radius, y - radius);
            }

            sector(ctx, pt.x, pt.y, size, startAngle, endAngle);
        },
        _isPattern: function _isPattern(style) {
            return !isString(style) && !('addColorStop' in style);
        },
        drawCross: function drawCross(ctx, x, y, lineWidth, color) {
            ctx.canvas._drawn = true;
            ctx.strokeStyle = color;
            ctx.lineWidth = lineWidth;
            ctx.beginPath();
            ctx.moveTo(x - 5, y);
            ctx.lineTo(x + 5, y);
            ctx.moveTo(x, y - 5);
            ctx.lineTo(x, y + 5);
            ctx.stroke();
        },
        copy: function copy(canvas, c) {
            var target = c || createEl('canvas');
            target.width = canvas.width;
            target.height = canvas.height;
            target.getContext('2d').drawImage(canvas, 0, 0);
            return target;
        }
    };

    function drawDashLine(ctx, startPoint, endPoint, dashArray) {
        var fromX = startPoint.x,
            fromY = startPoint.y,
            toX = endPoint.x,
            toY = endPoint.y;
        var pattern = dashArray;

        var lt = function lt(a, b) {
            return a <= b;
        };

        var gt = function gt(a, b) {
            return a >= b;
        };

        var capmin = function capmin(a, b) {
            return Math.min(a, b);
        };

        var capmax = function capmax(a, b) {
            return Math.max(a, b);
        };

        var checkX = {
            thereYet: gt,
            cap: capmin
        };
        var checkY = {
            thereYet: gt,
            cap: capmin
        };

        if (fromY - toY > 0) {
            checkY.thereYet = lt;
            checkY.cap = capmax;
        }

        if (fromX - toX > 0) {
            checkX.thereYet = lt;
            checkX.cap = capmax;
        }

        ctx.moveTo(fromX, fromY);
        var offsetX = fromX;
        var offsetY = fromY;
        var idx = 0,
            dash = true;
        var ang, len;

        while (!(checkX.thereYet(offsetX, toX) && checkY.thereYet(offsetY, toY))) {
            ang = Math.atan2(toY - fromY, toX - fromX);
            len = pattern[idx];
            offsetX = checkX.cap(toX, offsetX + Math.cos(ang) * len);
            offsetY = checkY.cap(toY, offsetY + Math.sin(ang) * len);

            if (dash) {
                ctx.lineTo(offsetX, offsetY);
            } else {
                ctx.moveTo(offsetX, offsetY);
            }

            idx = (idx + 1) % pattern.length;
            dash = !dash;
        }
    }

    var prefix = 'data:image/';

    function extractImageUrl(url) {
        if (url.substring(0, prefix.length) === prefix) {
            return url;
        }

        return extractCssUrl(url);
    }

    function copyProperties(ctx, savedCtx) {
        ctx.filter = savedCtx.filter;
        ctx.fillStyle = savedCtx.fillStyle;
        ctx.globalAlpha = savedCtx.globalAlpha;
        ctx.lineCap = savedCtx.lineCap;
        ctx.lineDashOffset = savedCtx.lineDashOffset;
        ctx.lineJoin = savedCtx.lineJoin;
        ctx.lineWidth = savedCtx.lineWidth;
        ctx.shadowBlur = savedCtx.shadowBlur;
        ctx.shadowColor = savedCtx.shadowColor;
        ctx.shadowOffsetX = savedCtx.shadowOffsetX;
        ctx.shadowOffsetY = savedCtx.shadowOffsetY;
        ctx.strokeStyle = savedCtx.strokeStyle;
    }

    var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};

    function createCommonjsModule(fn, module) {
        return module = { exports: {} }, fn(module, module.exports), module.exports;
    }

    var zousanMin = createCommonjsModule(function(module) {
        ! function(t) {

            function e(t) {
                if (t) {
                    var e = this;
                    t(function(t) {
                        e.resolve(t);
                    }, function(t) {
                        e.reject(t);
                    });
                }
            }

            function n(t, e) {
                if ("function" == typeof t.y) try {
                    var n = t.y.call(i, e);
                    t.p.resolve(n);
                } catch (o) {
                    t.p.reject(o);
                } else t.p.resolve(e);
            }

            function o(t, e) {
                if ("function" == typeof t.n) try {
                    var n = t.n.call(i, e);
                    t.p.resolve(n);
                } catch (o) {
                    t.p.reject(o);
                } else t.p.reject(e);
            }

            var r,
                i,
                c = "fulfilled",
                u = "rejected",
                s = "undefined",
                f = function() {
                    function e() {
                        for (; n.length - o;) {
                            try {
                                n[o]();
                            } catch (e) {
                                t.console && t.console.error(e);
                            }

                            n[o++] = i, o == r && (n.splice(0, r), o = 0);
                        }
                    }

                    var n = [],
                        o = 0,
                        r = 1024,
                        c = function() {
                            if (typeof MutationObserver !== s) {
                                var t = document.createElement("div"),
                                    n = new MutationObserver(e);
                                return n.observe(t, {
                                        attributes: !0
                                    }),
                                    function() {
                                        t.setAttribute("a", 0);
                                    };
                            }

                            return typeof setImmediate !== s ? function() {
                                setImmediate(e);
                            } : function() {
                                setTimeout(e, 0);
                            };
                        }();

                    return function(t) {
                        n.push(t), n.length - o == 1 && c();
                    };
                }();

            e.prototype = {
                resolve: function resolve(t) {
                    if (this.state === r) {
                        if (t === this) return this.reject(new TypeError("Attempt to resolve promise with self"));
                        var e = this;
                        if (t && ("function" == typeof t || "object" == typeof t)) try {
                            var o = !0,
                                i = t.then;
                            if ("function" == typeof i) return void i.call(t, function(t) {
                                o && (o = !1, e.resolve(t));
                            }, function(t) {
                                o && (o = !1, e.reject(t));
                            });
                        } catch (u) {
                            return void(o && this.reject(u));
                        }
                        this.state = c, this.v = t, e.c && f(function() {
                            for (var o = 0, r = e.c.length; r > o; o++) {
                                n(e.c[o], t);
                            }
                        });
                    }
                },
                reject: function reject(n) {
                    if (this.state === r) {
                        this.state = u, this.v = n;
                        var i = this.c;
                        i ? f(function() {
                            for (var t = 0, e = i.length; e > t; t++) {
                                o(i[t], n);
                            }
                        }) : !e.suppressUncaughtRejectionError && t.console && t.console.log("You upset Zousan. Please catch rejections: ", n, n ? n.stack : null);
                    }
                },
                then: function then(t, i) {
                    var u = new e(),
                        s = {
                            y: t,
                            n: i,
                            p: u
                        };
                    if (this.state === r) this.c ? this.c.push(s) : this.c = [s];
                    else {
                        var l = this.state,
                            a = this.v;
                        f(function() {
                            l === c ? n(s, a) : o(s, a);
                        });
                    }
                    return u;
                },
                "catch": function _catch(t) {
                    return this.then(null, t);
                },
                "finally": function _finally(t) {
                    return this.then(t, t);
                },
                timeout: function timeout(t, n) {
                    n = n || "Timeout";
                    var o = this;
                    return new e(function(e, r) {
                        setTimeout(function() {
                            r(Error(n));
                        }, t), o.then(function(t) {
                            e(t);
                        }, function(t) {
                            r(t);
                        });
                    });
                }
            }, e.resolve = function(t) {
                var n = new e();
                return n.resolve(t), n;
            }, e.reject = function(t) {
                var n = new e();
                return n.reject(t), n;
            }, e.all = function(t) {
                function n(n, c) {
                    n && "function" == typeof n.then || (n = e.resolve(n)), n.then(function(e) {
                        o[c] = e, r++, r == t.length && i.resolve(o);
                    }, function(t) {
                        i.reject(t);
                    });
                }

                for (var o = [], r = 0, i = new e(), c = 0; c < t.length; c++) {
                    n(t[c], c);
                }

                return t.length || i.resolve(o), i;
            }, module.exports && (module.exports = e), t.define && t.define.amd && t.define([], function() {
                return e;
            }), t.Zousan = e, e.soon = f;
        }("undefined" != typeof commonjsGlobal ? commonjsGlobal : commonjsGlobal);
    });

    var promise;

    if (typeof Promise !== 'undefined') {
        promise = Promise;
    } else {
        promise = zousanMin;
    }

    var Promise$1 = promise;

    var Eventable = function Eventable(Base) {
        return function(_Base) {
            _inheritsLoose(_class, _Base);

            function _class() {
                return _Base.apply(this, arguments) || this;
            }

            var _proto = _class.prototype;

            _proto.on = function on$$1(eventsOn, handler, context) {
                if (!eventsOn) {
                    return this;
                }

                if (!isString(eventsOn)) {
                    return this._switch('on', eventsOn, handler);
                }

                if (!handler) {
                    return this;
                }

                if (!this._eventMap) {
                    this._eventMap = {};
                }

                var eventTypes = eventsOn.toLowerCase().split(' ');
                var evtType;

                if (!context) {
                    context = this;
                }

                var handlerChain;

                for (var ii = 0, ll = eventTypes.length; ii < ll; ii++) {
                    evtType = eventTypes[ii];
                    handlerChain = this._eventMap[evtType];

                    if (!handlerChain) {
                        handlerChain = [];
                        this._eventMap[evtType] = handlerChain;
                    }

                    var l = handlerChain.length;

                    if (l > 0) {
                        for (var i = 0; i < l; i++) {
                            if (handler === handlerChain[i].handler && handlerChain[i].context === context) {
                                return this;
                            }
                        }
                    }

                    handlerChain.push({
                        handler: handler,
                        context: context
                    });
                }

                return this;
            };

            _proto.addEventListener = function addEventListener() {
                return this.on.apply(this, arguments);
            };

            _proto.once = function once(eventTypes, handler, context) {
                if (!isString(eventTypes)) {
                    var once = {};

                    for (var p in eventTypes) {
                        if (eventTypes.hasOwnProperty(p)) {
                            once[p] = this._wrapOnceHandler(p, eventTypes[p], context);
                        }
                    }

                    return this._switch('on', once);
                }

                var evetTypes = eventTypes.split(' ');

                for (var i = 0, l = evetTypes.length; i < l; i++) {
                    this.on(evetTypes[i], this._wrapOnceHandler(evetTypes[i], handler, context));
                }

                return this;
            };

            _proto.off = function off$$1(eventsOff, handler, context) {
                if (!this._eventMap || !eventsOff) {
                    return this;
                }

                if (!isString(eventsOff)) {
                    return this._switch('off', eventsOff, handler);
                }

                if (!handler) {
                    return this;
                }

                var eventTypes = eventsOff.split(' ');
                var eventType, listeners, wrapKey;

                if (!context) {
                    context = this;
                }

                for (var j = 0, jl = eventTypes.length; j < jl; j++) {
                    eventType = eventTypes[j].toLowerCase();
                    wrapKey = 'Z__' + eventType;
                    listeners = this._eventMap[eventType];

                    if (!listeners) {
                        return this;
                    }

                    for (var i = listeners.length - 1; i >= 0; i--) {
                        var listener = listeners[i];

                        if ((handler === listener.handler || handler === listener.handler[wrapKey]) && listener.context === context) {
                            delete listener.handler[wrapKey];
                            listeners.splice(i, 1);
                        }
                    }

                    if (!listeners.length) {
                        delete this._eventMap[eventType];
                    }
                }

                return this;
            };

            _proto.removeEventListener = function removeEventListener() {
                return this.off.apply(this, arguments);
            };

            _proto.listens = function listens(eventType, handler, context) {
                if (!this._eventMap || !isString(eventType)) {
                    return 0;
                }

                var handlerChain = this._eventMap[eventType.toLowerCase()];

                if (!handlerChain || !handlerChain.length) {
                    return 0;
                }

                if (!handler) {
                    return handlerChain.length;
                }

                for (var i = 0, len = handlerChain.length; i < len; i++) {
                    if (handler === handlerChain[i].handler && (isNil(context) || handlerChain[i].context === context)) {
                        return 1;
                    }
                }

                return 0;
            };

            _proto.getListeningEvents = function getListeningEvents() {
                if (!this._eventMap) {
                    return [];
                }

                return Object.keys(this._eventMap);
            };

            _proto.copyEventListeners = function copyEventListeners(target) {
                var eventMap = target._eventMap;

                if (!eventMap) {
                    return this;
                }

                var handlerChain;

                for (var eventType in eventMap) {
                    handlerChain = eventMap[eventType];

                    for (var i = 0, len = handlerChain.length; i < len; i++) {
                        this.on(eventType, handlerChain[i].handler, handlerChain[i].context);
                    }
                }

                return this;
            };

            _proto.fire = function fire() {
                if (this._eventParent) {
                    return this._eventParent.fire.apply(this._eventParent, arguments);
                }

                return this._fire.apply(this, arguments);
            };

            _proto._wrapOnceHandler = function _wrapOnceHandler(evtType, handler, context) {
                var me = this;
                var key = 'Z__' + evtType;
                var called = false;

                var fn = function onceHandler() {
                    if (called) {
                        return;
                    }

                    delete fn[key];
                    called = true;

                    if (context) {
                        handler.apply(context, arguments);
                    } else {
                        handler.apply(this, arguments);
                    }

                    me.off(evtType, onceHandler, this);
                };

                fn[key] = handler;
                return fn;
            };

            _proto._switch = function _switch(to, eventKeys, context) {
                for (var p in eventKeys) {
                    if (eventKeys.hasOwnProperty(p)) {
                        this[to](p, eventKeys[p], context);
                    }
                }

                return this;
            };

            _proto._clearListeners = function _clearListeners(eventType) {
                if (!this._eventMap || !isString(eventType)) {
                    return;
                }

                var handlerChain = this._eventMap[eventType.toLowerCase()];

                if (!handlerChain) {
                    return;
                }

                this._eventMap[eventType] = null;
            };

            _proto._clearAllListeners = function _clearAllListeners() {
                this._eventMap = null;
            };

            _proto._setEventParent = function _setEventParent(parent) {
                this._eventParent = parent;
                return this;
            };

            _proto._setEventTarget = function _setEventTarget(target) {
                this._eventTarget = target;
                return this;
            };

            _proto._fire = function _fire(eventType, param) {
                if (!this._eventMap) {
                    return this;
                }

                var handlerChain = this._eventMap[eventType.toLowerCase()];

                if (!handlerChain) {
                    return this;
                }

                if (!param) {
                    param = {};
                }

                param['type'] = eventType;
                param['target'] = this._eventTarget || this;
                var queue = handlerChain.slice(0);
                var context, bubble, passed;

                for (var i = 0, len = queue.length; i < len; i++) {
                    if (!queue[i]) {
                        continue;
                    }

                    context = queue[i].context;
                    bubble = true;
                    passed = extend({}, param);

                    if (context) {
                        bubble = queue[i].handler.call(context, passed);
                    } else {
                        bubble = queue[i].handler(passed);
                    }

                    if (bubble === false) {
                        if (param['domEvent']) {
                            stopPropagation(param['domEvent']);
                        }
                    }
                }

                return this;
            };

            return _class;
        }(Base);
    };

    var Handler = function() {
        function Handler(target) {
            this.target = target;
        }

        var _proto = Handler.prototype;

        _proto.enable = function enable() {
            if (this._enabled) {
                return this;
            }

            this._enabled = true;
            this.addHooks();
            return this;
        };

        _proto.disable = function disable() {
            if (!this._enabled) {
                return this;
            }

            this._enabled = false;
            this.removeHooks();
            return this;
        };

        _proto.enabled = function enabled() {
            return !!this._enabled;
        };

        _proto.remove = function remove() {
            this.disable();
            delete this.target;
            delete this.dom;
        };

        return Handler;
    }();

    var Handler$1 = Eventable(Handler);

    var Class = function() {
        function Class(options) {
            if (!this || !this.setOptions) {
                throw new Error('Class instance is being created without "new" operator.');
            }

            this.setOptions(options);
            this.callInitHooks();
        }

        var _proto = Class.prototype;

        _proto.callInitHooks = function callInitHooks() {
            var proto = Object.getPrototypeOf(this);

            this._visitInitHooks(proto);

            return this;
        };

        _proto.setOptions = function setOptions(options) {
            if (!this.hasOwnProperty('options')) {
                this.options = this.options ? Object.create(this.options) : {};
            }

            if (!options) {
                return this;
            }

            for (var i in options) {
                this.options[i] = options[i];
            }

            return this;
        };

        _proto.config = function config(conf) {
            if (!conf) {
                var config = {};

                for (var p in this.options) {
                    if (this.options.hasOwnProperty(p)) {
                        config[p] = this.options[p];
                    }
                }

                return config;
            } else {
                if (arguments.length === 2) {
                    var t = {};
                    t[conf] = arguments[1];
                    conf = t;
                }

                for (var i in conf) {
                    this.options[i] = conf[i];

                    if (this[i] && this[i] instanceof Handler$1) {
                        if (conf[i]) {
                            this[i].enable();
                        } else {
                            this[i].disable();
                        }
                    }
                }

                this.onConfig(conf);
            }

            return this;
        };

        _proto.onConfig = function onConfig() {};

        _proto._visitInitHooks = function _visitInitHooks(proto) {
            if (this._initHooksCalled) {
                return;
            }

            var parentProto = Object.getPrototypeOf(proto);

            if (parentProto._visitInitHooks) {
                parentProto._visitInitHooks.call(this, parentProto);
            }

            this._initHooksCalled = true;
            var hooks = proto._initHooks;

            if (hooks && hooks !== parentProto._initHooks) {
                for (var i = 0; i < hooks.length; i++) {
                    hooks[i].call(this);
                }
            }
        };

        Class.addInitHook = function addInitHook(fn) {
            for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
                args[_key - 1] = arguments[_key];
            }

            var init = typeof fn === 'function' ? fn : function() {
                this[fn].apply(this, args);
            };
            var proto = this.prototype;
            var parentProto = Object.getPrototypeOf(proto);

            if (!proto._initHooks || proto._initHooks === parentProto._initHooks) {
                proto._initHooks = [];
            }

            proto._initHooks.push(init);

            return this;
        };

        Class.include = function include() {
            for (var i = 0; i < arguments.length; i++) {
                extend(this.prototype, i < 0 || arguments.length <= i ? undefined : arguments[i]);
            }

            return this;
        };

        Class.mergeOptions = function mergeOptions(options) {
            var proto = this.prototype;
            var parentProto = Object.getPrototypeOf(proto);

            if (!proto.options || proto.options === parentProto.options) {
                proto.options = proto.options ? Object.create(proto.options) : {};
            }

            extend(proto.options, options);
            return this;
        };

        return Class;
    }();

    var registeredTypes = {};
    var JSONAble = (function(Base) {
        return function(_Base) {
            _inheritsLoose(_class, _Base);

            function _class() {
                return _Base.apply(this, arguments) || this;
            }

            _class.registerJSONType = function registerJSONType(type) {
                if (!type) {
                    return this;
                }

                registeredTypes[type] = this;
                return this;
            };

            _class.getJSONClass = function getJSONClass(type) {
                if (!type) {
                    return null;
                }

                return registeredTypes[type];
            };

            var _proto = _class.prototype;

            _proto.getJSONType = function getJSONType() {
                if (this._jsonType === undefined) {
                    var clazz = Object.getPrototypeOf(this).constructor;

                    for (var p in registeredTypes) {
                        if (registeredTypes[p] === clazz) {
                            this._jsonType = p;
                            break;
                        }
                    }
                }

                if (!this._jsonType) {
                    throw new Error('Found an unregistered geometry class!');
                }

                return this._jsonType;
            };

            return _class;
        }(Base);
    });

    function Handlerable(Base) {
        return function(_Base) {
            _inheritsLoose(_class, _Base);

            function _class() {
                return _Base.apply(this, arguments) || this;
            }

            var _proto = _class.prototype;

            _proto.addHandler = function addHandler(name, handlerClass) {
                if (!handlerClass) {
                    return this;
                }

                if (!this._handlers) {
                    this._handlers = [];
                }

                if (this[name]) {
                    this[name].enable();
                    return this;
                }

                var handler = this[name] = new handlerClass(this);

                this._handlers.push(handler);

                if (this.options[name]) {
                    handler.enable();
                }

                return this;
            };

            _proto.removeHandler = function removeHandler(name) {
                if (!name) {
                    return this;
                }

                var handler = this[name];

                if (handler) {
                    var hit = this._handlers.indexOf(handler);

                    if (hit >= 0) {
                        this._handlers.splice(hit, 1);
                    }

                    this[name].remove();
                    delete this[name];
                }

                return this;
            };

            _proto._clearHandlers = function _clearHandlers() {
                for (var i = 0, len = this._handlers.length; i < len; i++) {
                    this._handlers[i].remove();
                }

                this._handlers = [];
            };

            return _class;
        }(Base);
    }

    var START_EVENTS = 'touchstart mousedown';
    var MOVE_EVENTS = {
        mousedown: 'mousemove',
        touchstart: 'touchmove',
        pointerdown: 'touchmove',
        MSPointerDown: 'touchmove'
    };
    var END_EVENTS = {
        mousedown: 'mouseup',
        touchstart: 'touchend',
        pointerdown: 'touchend',
        MSPointerDown: 'touchend'
    };

    var DragHandler = function(_Handler) {
        _inheritsLoose(DragHandler, _Handler);

        function DragHandler(dom, options) {
            var _this;

            if (options === void 0) {
                options = {};
            }

            _this = _Handler.call(this, null) || this;
            _this.dom = dom;
            _this.options = options;
            return _this;
        }

        var _proto = DragHandler.prototype;

        _proto.enable = function enable() {
            if (!this.dom) {
                return this;
            }

            this._onMouseDown = function(e) {
                return this.onMouseDown(e);
            };

            on(this.dom, START_EVENTS, this._onMouseDown, this);
            return this;
        };

        _proto.disable = function disable() {
            if (!this.dom) {
                return this;
            }

            this._offEvents();

            off(this.dom, START_EVENTS, this._onMouseDown);
            delete this._onMouseDown;
            return this;
        };

        _proto.onMouseDown = function onMouseDown(event) {
            if (!this.options['rightclick'] && event.button === 2) {
                return;
            }

            if (event.touches && event.touches.length > 1) {
                return;
            }

            if (this.options['cancelOn'] && this.options['cancelOn'](event) === true) {
                return;
            }

            var dom = this.dom;

            if (dom.setCapture) {
                dom.setCapture();
            } else if (window.captureEvents) {
                window.captureEvents(window['Event'].MOUSEMOVE | window['Event'].MOUSEUP);
            }

            dom['ondragstart'] = function() {
                return false;
            };

            delete this.moved;
            var actual = event.touches ? event.touches[0] : event;
            this.startPos = new Point(actual.clientX, actual.clientY);
            on(document, MOVE_EVENTS[event.type], this.onMouseMove, this);
            on(document, END_EVENTS[event.type], this.onMouseUp, this);

            if (!this.options['ignoreMouseleave']) {
                on(this.dom, 'mouseleave', this.onMouseUp, this);
            }

            this.fire('mousedown', {
                'domEvent': event,
                'mousePos': new Point(actual.clientX, actual.clientY)
            });
        };

        _proto.onMouseMove = function onMouseMove(event) {
            if (event.touches && event.touches.length > 1) {
                if (this.moved) {
                    this.interupted = true;
                    this.onMouseUp(event);
                }

                return;
            }

            var actual = event.touches ? event.touches[0] : event;
            var newPos = new Point(actual.clientX, actual.clientY),
                offset = newPos.sub(this.startPos);

            if (!offset.x && !offset.y) {
                return;
            }

            if (!this.moved) {
                this.fire('dragstart', {
                    'domEvent': event,
                    'mousePos': this.startPos.copy()
                });
                this.moved = true;
            } else {
                this.fire('dragging', {
                    'domEvent': event,
                    'mousePos': new Point(actual.clientX, actual.clientY)
                });
            }
        };

        _proto.onMouseUp = function onMouseUp(event) {
            var actual = event.changedTouches ? event.changedTouches[0] : event;

            this._offEvents();

            var param = {
                'domEvent': event
            };

            if (isNumber(actual.clientX)) {
                param['mousePos'] = new Point(parseInt(actual.clientX, 0), parseInt(actual.clientY, 0));
            }

            if (this.moved) {
                param.interupted = this.interupted;
                this.fire('dragend', param);
                delete this.interupted;
                delete this.moved;
            }

            this.fire('mouseup', param);
        };

        _proto._offEvents = function _offEvents() {
            var dom = this.dom;
            off(dom, 'mouseleave', this.onMouseUp, this);

            if (typeof document === 'undefined' || typeof window === 'undefined') {
                return;
            }

            for (var i in MOVE_EVENTS) {
                off(document, MOVE_EVENTS[i], this.onMouseMove, this);
                off(document, END_EVENTS[i], this.onMouseUp, this);
            }

            if (dom['releaseCapture']) {
                dom['releaseCapture']();
            } else if (window.captureEvents) {
                window.captureEvents(window['Event'].MOUSEMOVE | window['Event'].MOUSEUP);
            }
        };

        return DragHandler;
    }(Handler$1);

    var Coordinate = function(_Position) {
        _inheritsLoose(Coordinate, _Position);

        function Coordinate() {
            return _Position.apply(this, arguments) || this;
        }

        Coordinate.toNumberArrays = function toNumberArrays(coordinates) {
            if (!Array.isArray(coordinates)) {
                return [coordinates.x, coordinates.y];
            }

            return forEachCoord(coordinates, function(coord) {
                return [coord.x, coord.y];
            });
        };

        Coordinate.toCoordinates = function toCoordinates(coordinates) {
            if (isNumber(coordinates[0]) && isNumber(coordinates[1])) {
                return new Coordinate(coordinates);
            }

            var result = [];

            for (var i = 0, len = coordinates.length; i < len; i++) {
                var child = coordinates[i];

                if (Array.isArray(child)) {
                    if (isNumber(child[0])) {
                        result.push(new Coordinate(child));
                    } else {
                        result.push(Coordinate.toCoordinates(child));
                    }
                } else {
                    result.push(new Coordinate(child));
                }
            }

            return result;
        };

        return Coordinate;
    }(Position);

    var CRS = function() {
        function CRS(type, properties) {
            this.type = type;
            this.properties = properties;
        }

        CRS.createProj4 = function createProj4(proj) {
            return new CRS('proj4', {
                'proj': proj
            });
        };

        CRS.fromProjectionCode = function fromProjectionCode(code) {
            if (!code) {
                return null;
            }

            code = code.toUpperCase().replace(':', '');
            return CRS[code] || null;
        };

        return CRS;
    }();

    CRS.WGS84 = CRS.createProj4('+proj=longlat +datum=WGS84 +no_defs');
    CRS.EPSG4326 = CRS.WGS84;
    CRS.EPSG3857 = CRS.createProj4('+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext  +no_defs');
    CRS.IDENTITY = CRS.createProj4('+proj=identity +no_defs');
    CRS.CGCS2000 = CRS.createProj4('+proj=longlat +datum=CGCS2000');
    CRS.EPSG4490 = CRS.CGCS2000;
    CRS.BD09LL = CRS.createProj4('+proj=longlat +datum=BD09');
    CRS.GCJ02 = CRS.createProj4('+proj=longlat +datum=GCJ02');

    var TEMP_POINT0 = new Point(0, 0);
    var TEMP_COORD0 = new Coordinate(0, 0);
    var TEMP_COORD1 = new Coordinate(0, 0);
    var TEMP_COORD2 = new Coordinate(0, 0);
    var TEMP_COORD3 = new Coordinate(0, 0);
    var TEMP_COORD4 = new Coordinate(0, 0);
    var TEMP_COORD5 = new Coordinate(0, 0);
    var TEMP_COORD6 = new Coordinate(0, 0);
    var TEMP_COORD7 = new Coordinate(0, 0);
    var MINMAX = [];
    var TEMP_EXTENT;
    var TEMP_COMBINE = [];

    var Extent = function() {
        function Extent(p1, p2, p3, p4) {
            this._clazz = Coordinate;
            var l = arguments.length;
            var proj = l > 0 ? arguments[l - 1] : null;

            if (proj && proj.unproject) {
                this.projection = arguments[l - 1];
            }

            this._dirty = true;

            this._initialize(p1, p2, p3, p4);
        }

        var _proto = Extent.prototype;

        _proto._initialize = function _initialize(p1, p2, p3, p4) {
            this.xmin = null;
            this.xmax = null;
            this.ymin = null;
            this.ymax = null;

            if (isNil(p1)) {
                return;
            }

            var projection = this.projection;

            if (isNumber(p1) && isNumber(p2) && isNumber(p3) && isNumber(p4)) {
                if (projection) {
                    this.set(p1, p2, p3, p4);
                } else {
                    this.set(Math.min(p1, p3), Math.min(p2, p4), Math.max(p1, p3), Math.max(p2, p4));
                }

                return;
            } else if (Array.isArray(p1)) {
                if (projection) {
                    this.set(p1[0], p1[1], p1[2], p1[3]);
                } else {
                    this.set(Math.min(p1[0], p1[2]), Math.min(p1[1], p1[3]), Math.max(p1[0], p1[2]), Math.max(p1[1], p1[3]));
                }
            } else if (isNumber(p1.x) && isNumber(p2.x) && isNumber(p1.y) && isNumber(p2.y)) {
                if (projection) {
                    this.set(p1.x, p1.y, p2.x, p2.y);
                } else {
                    if (p1.x > p2.x) {
                        this['xmin'] = p2.x;
                        this['xmax'] = p1.x;
                    } else {
                        this['xmin'] = p1.x;
                        this['xmax'] = p2.x;
                    }

                    if (p1.y > p2.y) {
                        this['ymin'] = p2.y;
                        this['ymax'] = p1.y;
                    } else {
                        this['ymin'] = p1.y;
                        this['ymax'] = p2.y;
                    }
                }
            } else if (isNumber(p1['xmin']) && isNumber(p1['xmax']) && isNumber(p1['ymin']) && isNumber(p1['ymax'])) {
                this.set(p1['xmin'], p1['ymin'], p1['xmax'], p1['ymax']);
            }
        };

        _proto._add = function _add(p) {
            this._dirty = true;

            if (!isNil(p.x)) {
                this['xmin'] += p.x;
                this['ymin'] += p.y;
                this['xmax'] += p.x;
                this['ymax'] += p.y;
            } else if (!isNil(p.xmin)) {
                this['xmin'] += p.xmin;
                this['ymin'] += p.ymin;
                this['xmax'] += p.xmax;
                this['ymax'] += p.ymax;
            } else if (!isNil(p[0])) {
                this['xmin'] += p[0];
                this['ymin'] += p[1];
                this['xmax'] += p[0];
                this['ymax'] += p[1];
            }

            return this;
        };

        _proto.add = function add() {
            var e = new this.constructor(this['xmin'], this['ymin'], this['xmax'], this['ymax'], this.projection);
            return e._add.apply(e, arguments);
        };

        _proto._scale = function _scale(s) {
            this._dirty = true;
            this['xmin'] *= s;
            this['ymin'] *= s;
            this['xmax'] *= s;
            this['ymax'] *= s;
            return this;
        };

        _proto._sub = function _sub(p) {
            this._dirty = true;

            if (!isNil(p.x)) {
                this['xmin'] -= p.x;
                this['ymin'] -= p.y;
                this['xmax'] -= p.x;
                this['ymax'] -= p.y;
            } else if (!isNil(p.xmin)) {
                this['xmin'] -= p.xmin;
                this['ymin'] -= p.ymin;
                this['xmax'] -= p.xmax;
                this['ymax'] -= p.ymax;
            } else if (!isNil(p[0])) {
                this['xmin'] -= p[0];
                this['ymin'] -= p[1];
                this['xmax'] -= p[0];
                this['ymax'] -= p[1];
            }

            return this;
        };

        _proto._substract = function _substract() {
            return this._sub.apply(this, arguments);
        };

        _proto.sub = function sub() {
            var e = new this.constructor(this['xmin'], this['ymin'], this['xmax'], this['ymax'], this.projection);
            return e._sub.apply(e, arguments);
        };

        _proto.substract = function substract() {
            return this.sub.apply(this, arguments);
        };

        _proto.round = function round() {
            return new this.constructor(Math.round(this['xmin']), Math.round(this['ymin']), Math.round(this['xmax']), Math.round(this['ymax']), this.projection);
        };

        _proto._round = function _round() {
            this._dirty = true;
            this['xmin'] = Math.round(this['xmin']);
            this['ymin'] = Math.round(this['ymin']);
            this['xmax'] = Math.round(this['xmax']);
            this['ymax'] = Math.round(this['ymax']);
            return this;
        };

        _proto.getMin = function getMin(out) {
            if (out) {
                out.set(this['xmin'], this['ymin']);
                return out;
            }

            return new this._clazz(this['xmin'], this['ymin']);
        };

        _proto.getMax = function getMax(out) {
            if (out) {
                out.set(this['xmax'], this['ymax']);
                return out;
            }

            return new this._clazz(this['xmax'], this['ymax']);
        };

        _proto.getCenter = function getCenter(out) {
            var x = (this['xmin'] + this['xmax']) / 2;
            var y = (this['ymin'] + this['ymax']) / 2;

            if (out) {
                out.set(x, y);
                return out;
            }

            return new this._clazz(x, y);
        };

        _proto.isValid = function isValid() {
            return !isNil(this['xmin']) && !isNil(this['ymin']) && !isNil(this['xmax']) && !isNil(this['ymax']);
        };

        _proto.equals = function equals(ext2) {
            return this['xmin'] === ext2['xmin'] && this['xmax'] === ext2['xmax'] && this['ymin'] === ext2['ymin'] && this['ymax'] === ext2['ymax'];
        };

        _proto.intersects = function intersects(ext2) {
            this._project(this);

            this._project(ext2);

            var rxmin = Math.max(this['pxmin'], ext2['pxmin']);
            var rymin = Math.max(this['pymin'], ext2['pymin']);
            var rxmax = Math.min(this['pxmax'], ext2['pxmax']);
            var rymax = Math.min(this['pymax'], ext2['pymax']);
            var intersects = !(rxmin > rxmax || rymin > rymax);
            return intersects;
        };

        _proto.within = function within(extent) {
            this._project(this);

            this._project(extent);

            return this.pxmin >= extent.pxmin && this.pxmax <= extent.pxmax && this.pymin >= extent.pymin && this.pymax <= extent.pymax;
        };

        _proto.contains = function contains(c) {
            if (!c) {
                return false;
            }

            this._project(this);

            var proj = this.projection;

            if (proj) {
                if (c.x !== undefined) {
                    var coord = TEMP_COORD0;

                    if (Array.isArray(c)) {
                        coord.x = c[0];
                        coord.y = c[1];
                    } else {
                        coord.x = c.x;
                        coord.y = c.y;
                    }

                    c = proj.project(coord, coord);
                } else if (c.xmin !== undefined) {
                    this._project(c);
                }
            }

            return (c.x || c.pxmin || 0) >= this.pxmin && (c.x || c.pxmax || 0) <= this.pxmax && (c.y || c.pymin || 0) >= this.pymin && (c.y || c.pymax || 0) <= this.pymax;
        };

        _proto.getWidth = function getWidth() {
            return Math.abs(this['xmax'] - this['xmin']);
        };

        _proto.getHeight = function getHeight() {
            return Math.abs(this['ymax'] - this['ymin']);
        };

        _proto.getSize = function getSize() {
            return new Size(this.getWidth(), this.getHeight());
        };

        _proto.set = function set(xmin, ymin, xmax, ymax) {
            this.xmin = xmin;
            this.ymin = ymin;
            this.xmax = xmax;
            this.ymax = ymax;
            this._dirty = true;
            return this;
        };

        _proto.__combine = function __combine(extent) {
            if (extent.x !== undefined) {
                TEMP_EXTENT.xmin = TEMP_EXTENT.xmax = extent.x;
                TEMP_EXTENT.ymin = TEMP_EXTENT.ymax = extent.y;
                extent = TEMP_EXTENT;
            }

            this._project(extent);

            this._project(this);

            var inited = isNumber(this.pxmin);
            var xmin, ymin, xmax, ymax;

            if (!inited) {
                xmin = extent['pxmin'];
                ymin = extent['pymin'];
                xmax = extent['pxmax'];
                ymax = extent['pymax'];
            } else {
                xmin = Math.min(this['pxmin'], extent['pxmin']);
                ymin = Math.min(this['pymin'], extent['pymin']);
                xmax = Math.max(this['pxmax'], extent['pxmax']);
                ymax = Math.max(this['pymax'], extent['pymax']);
            }

            var proj = this.projection;

            if (proj) {
                TEMP_COORD1.set(xmin, ymin);
                TEMP_COORD2.set(xmax, ymax);
                var min = proj.unproject(TEMP_COORD1, TEMP_COORD1),
                    max = proj.unproject(TEMP_COORD2, TEMP_COORD2);
                xmin = min.x;
                ymin = min.y;
                xmax = max.x;
                ymax = max.y;
            }

            TEMP_COMBINE[0] = xmin;
            TEMP_COMBINE[1] = ymin;
            TEMP_COMBINE[2] = xmax;
            TEMP_COMBINE[3] = ymax;
            return TEMP_COMBINE;
        };

        _proto._combine = function _combine(extent) {
            if (!extent || extent.isValid && !extent.isValid()) {
                return this;
            }

            var ext = this.__combine(extent);

            this.set(ext[0], ext[1], ext[2], ext[3]);
            this._dirty = true;
            return this;
        };

        _proto.combine = function combine(extent) {
            if (!extent || extent.isValid && !extent.isValid()) {
                return this;
            }

            var ext = this.__combine(extent);

            return new this.constructor(ext[0], ext[1], ext[2], ext[3], this.projection);
        };

        _proto.intersection = function intersection(extent) {
            if (!this.intersects(extent)) {
                return null;
            }

            TEMP_COORD3.x = Math.max(this['pxmin'], extent['pxmin']);
            TEMP_COORD3.y = Math.max(this['pymin'], extent['pymin']);
            TEMP_COORD4.x = Math.min(this['pxmax'], extent['pxmax']);
            TEMP_COORD4.y = Math.min(this['pymax'], extent['pymax']);
            var min = TEMP_COORD3,
                max = TEMP_COORD4;
            var proj = this.projection;

            if (proj) {
                min = proj.unproject(min, min);
                max = proj.unproject(max, max);
            }

            return new this.constructor(min, max, proj);
        };

        _proto.expand = function expand(distance) {
            var w, h;

            if (!isNumber(distance)) {
                w = distance['width'] || distance['x'] || distance[0] || 0;
                h = distance['height'] || distance['y'] || distance[1] || 0;
            } else {
                w = h = distance;
            }

            return new this.constructor(this['xmin'] - w, this['ymin'] - h, this['xmax'] + w, this['ymax'] + h, this.projection);
        };

        _proto._expand = function _expand(distance) {
            var w, h;

            if (!isNumber(distance)) {
                w = distance['width'] || distance['x'] || distance[0] || 0;
                h = distance['height'] || distance['y'] || distance[1] || 0;
            } else {
                w = h = distance;
            }

            this['xmin'] -= w;
            this['ymin'] -= h;
            this['xmax'] += w;
            this['ymax'] += h;
            this._dirty = true;
            return this;
        };

        _proto.toJSON = function toJSON() {
            return {
                'xmin': this['xmin'],
                'ymin': this['ymin'],
                'xmax': this['xmax'],
                'ymax': this['ymax']
            };
        };

        _proto.toArray = function toArray() {
            var xmin = this['xmin'],
                ymin = this['ymin'],
                xmax = this['xmax'],
                ymax = this['ymax'];
            return [new this._clazz([xmin, ymax]), new this._clazz([xmax, ymax]), new this._clazz([xmax, ymin]), new this._clazz([xmin, ymin]), new this._clazz([xmin, ymax])];
        };

        _proto.toString = function toString() {
            return this.xmin + "," + this.ymin + "," + this.xmax + "," + this.ymax;
        };

        _proto.copy = function copy() {
            return new this.constructor(this['xmin'], this['ymin'], this['xmax'], this['ymax'], this.projection);
        };

        _proto.convertTo = function convertTo(fn, out) {
            if (!this.isValid()) {
                return null;
            }

            var e = out || new this.constructor();

            if (out) {
                e.set(null, null, null, null);
            }

            var coord;

            if (this._clazz === Coordinate) {
                coord = TEMP_COORD5;
            } else if (this._clazz === Point) {
                coord = TEMP_POINT0;
            }

            coord.x = this.xmin;
            coord.y = this.ymax;

            e._combine(fn(coord));

            coord.x = this.xmax;

            e._combine(fn(coord));

            coord.y = this.ymin;

            e._combine(fn(coord));

            coord.x = this.xmin;

            e._combine(fn(coord));

            return e;
        };

        _proto._project = function _project(ext) {
            if (!ext || !ext.isValid()) {
                if (ext) {
                    ext.pxmin = ext.pxmax = ext.pymin = ext.pymax = null;
                }

                return;
            }

            var proj = this.projection;

            if (proj) {
                if (ext._dirty) {
                    TEMP_COORD6.set(ext.xmax, ext.ymin);
                    TEMP_COORD7.set(ext.xmin, ext.ymax);
                    MINMAX[0] = TEMP_COORD6;
                    MINMAX[1] = TEMP_COORD7;
                    var minmax = proj.projectCoords(MINMAX);
                    var min = minmax[0],
                        max = minmax[1];
                    ext.pxmin = Math.min(min.x, max.x);
                    ext.pymin = Math.min(min.y, max.y);
                    ext.pxmax = Math.max(min.x, max.x);
                    ext.pymax = Math.max(min.y, max.y);
                }

                delete ext._dirty;
            } else {
                ext.pxmin = ext.xmin;
                ext.pxmax = ext.xmax;
                ext.pymin = ext.ymin;
                ext.pymax = ext.ymax;
            }
        };

        return Extent;
    }();

    TEMP_EXTENT = new Extent(0, 0, 0, 0);

    var PointExtent = function(_Extent) {
        _inheritsLoose(PointExtent, _Extent);

        function PointExtent(p1, p2, p3, p4) {
            var _this;

            _this = _Extent.call(this, p1, p2, p3, p4) || this;
            _this._clazz = Point;
            return _this;
        }

        return PointExtent;
    }(Extent);

    var Transformation = function() {
        function Transformation(matrix) {
            this.matrix = matrix;
        }

        var _proto = Transformation.prototype;

        _proto.transform = function transform(coordinates, scale, out) {
            var x = this.matrix[0] * (coordinates.x - this.matrix[2]) / scale;
            var y = -this.matrix[1] * (coordinates.y - this.matrix[3]) / scale;

            if (out) {
                out.x = x;
                out.y = y;
                return out;
            }

            return new Point(x, y);
        };

        _proto.untransform = function untransform(point, scale, out) {
            var x = point.x * scale / this.matrix[0] + this.matrix[2];
            var y = point.y * scale / -this.matrix[1] + this.matrix[3];

            if (out) {
                out.x = x;
                out.y = y;
                return out;
            }

            return new Coordinate(x, y);
        };

        return Transformation;
    }();

    var Common = {
        project: function project() {},
        unproject: function unproject() {},
        projectCoords: function projectCoords(coordinates) {
            var _this = this;

            if (!coordinates) {
                return [];
            }

            if (!Array.isArray(coordinates)) {
                return this.project(coordinates);
            }

            if (coordinates.length === 0) {
                return [];
            }

            if (!this.isSphere()) {
                return forEachCoord(coordinates, this.project, this);
            }

            if (Array.isArray(coordinates[0])) {
                return coordinates.map(function(coords) {
                    return _this.projectCoords(coords);
                });
            } else {
                var circum = this.getCircum();
                var extent = this.getSphereExtent(),
                    sx = extent.sx,
                    sy = extent.sy;
                var wrapX, wrapY;
                var pre = coordinates[0],
                    current,
                    dx,
                    dy,
                    p;
                var prj = [this.project(pre)];

                for (var i = 1, l = coordinates.length; i < l; i++) {
                    current = coordinates[i];
                    dx = current.x - pre.x;
                    dy = current.y - pre.y;
                    p = this.project(current);

                    if (Math.abs(dx) > 180) {
                        if (wrapX === undefined) {
                            wrapX = current.x > pre.x;
                        }

                        if (wrapX) {
                            p._add(-circum.x * sign(dx) * sx, 0);

                            current._add(-360 * sign(dx), 0);
                        }
                    }

                    if (Math.abs(dy) > 90) {
                        if (wrapY === undefined) {
                            wrapY = current.y < pre.y;
                        }

                        if (wrapY) {
                            p._add(0, -circum.y * sign(dy) * sy);

                            current._add(0, -180 * sign(dy));
                        }
                    }

                    pre = current;
                    prj.push(p);
                }

                return prj;
            }
        },
        unprojectCoords: function unprojectCoords(projCoords) {
            if (!projCoords) {
                return [];
            }

            if (!Array.isArray(projCoords)) {
                return this.unproject(projCoords);
            }

            return forEachCoord(projCoords, this.unproject, this);
        },
        isSphere: function isSphere() {
            return !!this.sphere;
        },
        isOutSphere: function isOutSphere(pcoord) {
            if (!this.isSphere()) {
                return false;
            }

            var extent = this.getSphereExtent();
            return !extent.contains(pcoord);
        },
        wrapCoord: function wrapCoord(pcoord) {
            if (!this.isSphere()) {
                return pcoord;
            }

            var extent = this.getSphereExtent();
            var wrapped = new Coordinate(pcoord);

            if (!extent.contains(wrapped)) {
                wrapped.x = wrap(pcoord.x, extent.xmin, extent.xmax);
                wrapped.y = wrap(pcoord.y, extent.ymin, extent.ymax);
            }

            return wrapped;
        },
        getCircum: function getCircum() {
            if (!this.circum && this.isSphere()) {
                var extent = this.getSphereExtent();
                this.circum = {
                    x: extent.getWidth(),
                    y: extent.getHeight()
                };
            }

            return this.circum;
        },
        getSphereExtent: function getSphereExtent() {
            if (!this.extent && this.isSphere()) {
                var max = this.project(new Coordinate(180, 90)),
                    min = this.project(new Coordinate(-180, -90));
                this.extent = new Extent(min, max, this);
                this.extent.sx = max.x > min.x ? 1 : -1;
                this.extent.sy = max.y > min.y ? 1 : -1;
            }

            return this.extent;
        }
    };

    var Common$1 = {
        measureLength: function measureLength(c1, c2) {
            if (!Array.isArray(c1)) {
                return this.measureLenBetween(c1, c2);
            }

            var len = 0;

            for (var i = 0, l = c1.length; i < l - 1; i++) {
                len += this.measureLenBetween(c1[i], c1[i + 1]);
            }

            return len;
        }
    };

    var Identity = extend({
        'measure': 'IDENTITY',
        measureLenBetween: function measureLenBetween(c1, c2) {
            if (!c1 || !c2) {
                return 0;
            }

            try {
                return Math.sqrt(Math.pow(c1.x - c2.x, 2) + Math.pow(c1.y - c2.y, 2));
            } catch (err) {
                return 0;
            }
        },
        measureArea: function measureArea(coordinates) {
            if (!Array.isArray(coordinates)) {
                return 0;
            }

            var area = 0;

            for (var i = 0, len = coordinates.length; i < len; i++) {
                var c1 = coordinates[i];
                var c2 = null;

                if (i === len - 1) {
                    c2 = coordinates[0];
                } else {
                    c2 = coordinates[i + 1];
                }

                area += c1.x * c2.y - c1.y * c2.x;
            }

            return Math.abs(area / 2);
        },
        locate: function locate(c, xDist, yDist) {
            c = new Coordinate(c.x, c.y);
            return this._locate(c, xDist, yDist);
        },
        _locate: function _locate(c, xDist, yDist) {
            if (!c) {
                return null;
            }

            if (!xDist) {
                xDist = 0;
            }

            if (!yDist) {
                yDist = 0;
            }

            if (!xDist && !yDist) {
                return c;
            }

            c.x = c.x + xDist;
            c.y = c.y + yDist;
            return c;
        },
        rotate: function rotate(c, pivot, angle) {
            c = new Coordinate(c.x, c.y);
            return this._rotate(c, pivot, angle);
        },
        _rotate: function() {
            var tmp = new Point(0, 0);
            return function(c, pivot, angle) {
                tmp.x = c.x - pivot.x;
                tmp.y = c.y - pivot.y;

                tmp._rotate(angle * Math.PI / 180);

                c.x = pivot.x + tmp.x;
                c.y = pivot.y + tmp.y;
                return c;
            };
        }()
    }, Common$1);

    var Sphere = function() {
        function Sphere(radius) {
            this.radius = radius;
        }

        var _proto = Sphere.prototype;

        _proto.measureLenBetween = function measureLenBetween(c1, c2) {
            if (!c1 || !c2) {
                return 0;
            }

            var b = toRadian(c1.y);
            var d = toRadian(c2.y),
                e = b - d,
                f = toRadian(c1.x) - toRadian(c2.x);
            b = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(e / 2), 2) + Math.cos(b) * Math.cos(d) * Math.pow(Math.sin(f / 2), 2)));
            b *= this.radius;
            return Math.round(b * 1E5) / 1E5;
        };

        _proto.measureArea = function measureArea(coordinates) {
            var a = toRadian(this.radius);
            var b = 0,
                c = coordinates,
                d = c.length;

            if (d < 3) {
                return 0;
            }

            var i;

            for (i = 0; i < d - 1; i++) {
                var e = c[i],
                    f = c[i + 1];
                b += e.x * a * Math.cos(toRadian(e.y)) * f.y * a - f.x * a * Math.cos(toRadian(f.y)) * e.y * a;
            }

            d = c[i];
            c = c[0];
            b += d.x * a * Math.cos(toRadian(d.y)) * c.y * a - c.x * a * Math.cos(toRadian(c.y)) * d.y * a;
            return 0.5 * Math.abs(b);
        };

        _proto.locate = function locate(c, xDist, yDist) {
            c = new Coordinate(c.x, c.y);
            return this._locate(c, xDist, yDist);
        };

        _proto._locate = function _locate(c, xDist, yDist) {
            if (!c) {
                return null;
            }

            if (!xDist) {
                xDist = 0;
            }

            if (!yDist) {
                yDist = 0;
            }

            if (!xDist && !yDist) {
                return c;
            }

            var x, y;
            var ry = toRadian(c.y);

            if (yDist !== 0) {
                var dy = Math.abs(yDist);
                var sy = Math.sin(dy / (2 * this.radius)) * 2;
                ry = ry + sy * (yDist > 0 ? 1 : -1);
                y = wrap(ry * 180 / Math.PI, -90, 90);
            } else {
                y = c.y;
            }

            if (xDist !== 0) {
                var dx = Math.abs(xDist);
                var rx = toRadian(c.x);
                var sx = 2 * Math.sqrt(Math.pow(Math.sin(dx / (2 * this.radius)), 2) / Math.pow(Math.cos(ry), 2));
                rx = rx + sx * (xDist > 0 ? 1 : -1);
                x = wrap(rx * 180 / Math.PI, -180, 180);
            } else {
                x = c.x;
            }

            c.x = x;
            c.y = y;
            return c;
        };

        _proto.rotate = function rotate(c, pivot, angle) {
            c = new Coordinate(c);
            return this._rotate(c, pivot, angle);
        };

        _proto._rotate = function _rotate(c, pivot, angle) {
            var initialAngle = rhumbBearing(pivot, c);
            var finalAngle = initialAngle - angle;
            var distance = this.measureLenBetween(pivot, c);
            c.x = pivot.x;
            c.y = pivot.y;
            return calculateRhumbDestination(c, distance, finalAngle, this.radius);
        };

        return Sphere;
    }();

    function rhumbBearing(start, end, options) {
        if (options === void 0) {
            options = {};
        }

        var bear360;
        if (options.final) bear360 = calculateRhumbBearing(end, start);
        else bear360 = calculateRhumbBearing(start, end);
        var bear180 = bear360 > 180 ? -(360 - bear360) : bear360;
        return bear180;
    }

    function calculateRhumbBearing(from, to) {
        var phi1 = toRadian(from.y);
        var phi2 = toRadian(to.y);
        var deltaLambda = toRadian(to.x - from.x);
        if (deltaLambda > Math.PI) deltaLambda -= 2 * Math.PI;
        if (deltaLambda < -Math.PI) deltaLambda += 2 * Math.PI;
        var deltaPsi = Math.log(Math.tan(phi2 / 2 + Math.PI / 4) / Math.tan(phi1 / 2 + Math.PI / 4));
        var theta = Math.atan2(deltaLambda, deltaPsi);
        return (toDegree(theta) + 360) % 360;
    }

    function calculateRhumbDestination(origin, distance, bearing, radius) {
        var delta = distance / radius;
        var lambda1 = origin.x * Math.PI / 180;
        var phi1 = toRadian(origin.y);
        var theta = toRadian(bearing);
        var DeltaPhi = delta * Math.cos(theta);
        var phi2 = phi1 + DeltaPhi;
        if (Math.abs(phi2) > Math.PI / 2) phi2 = phi2 > 0 ? Math.PI - phi2 : -Math.PI - phi2;
        var DeltaPsi = Math.log(Math.tan(phi2 / 2 + Math.PI / 4) / Math.tan(phi1 / 2 + Math.PI / 4));
        var q = Math.abs(DeltaPsi) > 10e-12 ? DeltaPhi / DeltaPsi : Math.cos(phi1);
        var DeltaLambda = delta * Math.sin(theta) / q;
        var lambda2 = lambda1 + DeltaLambda;
        origin.x = (lambda2 * 180 / Math.PI + 540) % 360 - 180;
        origin.y = phi2 * 180 / Math.PI;
        return origin;
    }

    var WGS84Sphere = extend({
        'measure': 'EPSG:4326',
        sphere: new Sphere(6378137),
        measureLenBetween: function measureLenBetween() {
            return this.sphere.measureLenBetween.apply(this.sphere, arguments);
        },
        measureArea: function measureArea() {
            return this.sphere.measureArea.apply(this.sphere, arguments);
        },
        _locate: function _locate() {
            return this.sphere._locate.apply(this.sphere, arguments);
        },
        locate: function locate() {
            return this.sphere.locate.apply(this.sphere, arguments);
        },
        _rotate: function _rotate() {
            return this.sphere._rotate.apply(this.sphere, arguments);
        },
        rotate: function rotate() {
            return this.sphere.rotate.apply(this.sphere, arguments);
        }
    }, Common$1);
    var BaiduSphere = extend({
        'measure': 'BAIDU',
        sphere: new Sphere(6370996.81),
        measureLenBetween: function measureLenBetween() {
            return this.sphere.measureLenBetween.apply(this.sphere, arguments);
        },
        measureArea: function measureArea() {
            return this.sphere.measureArea.apply(this.sphere, arguments);
        },
        _locate: function _locate() {
            return this.sphere._locate.apply(this.sphere, arguments);
        },
        locate: function locate() {
            return this.sphere.locate.apply(this.sphere, arguments);
        },
        _rotate: function _rotate() {
            return this.sphere._rotate.apply(this.sphere, arguments);
        },
        rotate: function rotate() {
            return this.sphere.rotate.apply(this.sphere, arguments);
        }
    }, Common$1);

    var DEFAULT = WGS84Sphere;
    var measurers = {};

    function registerMeasurer(m) {
        measurers[m.measure] = m;
    }

    registerMeasurer(Identity);
    registerMeasurer(WGS84Sphere);
    registerMeasurer(BaiduSphere);
    var Measurer = {
        getInstance: function getInstance(name) {
            if (!name) {
                return DEFAULT;
            }

            for (var p in measurers) {
                if (hasOwn(measurers, p)) {
                    var mName = measurers[p]['measure'];

                    if (!mName) {
                        continue;
                    }

                    if (name.toLowerCase() === mName.toLowerCase()) {
                        return measurers[p];
                    }
                }
            }

            return null;
        }
    };

    var index$2 = /*#__PURE__*/ Object.freeze({
        Identity: Identity,
        DEFAULT: DEFAULT,
        Measurer: Measurer,
        WGS84Sphere: WGS84Sphere,
        BaiduSphere: BaiduSphere
    });

    var delta = 1E-7;
    var EPSG3857 = extend({}, Common, {
        code: 'EPSG:3857',
        rad: Math.PI / 180,
        metersPerDegree: 6378137 * Math.PI / 180,
        maxLatitude: 85.0511287798,
        project: function project(lnglat, out) {
            var rad = this.rad,
                metersPerDegree = this.metersPerDegree,
                max = this.maxLatitude;
            var lng = lnglat.x,
                lat = Math.max(Math.min(max, lnglat.y), -max);
            var c;

            if (lat === 0) {
                c = 0;
            } else {
                c = Math.log(Math.tan((90 + lat) * rad / 2)) / rad;
            }

            var x = lng * metersPerDegree;
            var y = c * metersPerDegree;

            if (out) {
                out.x = x;
                out.y = y;
                return out;
            }

            return new Coordinate(x, y);
        },
        unproject: function unproject(pLnglat, out) {
            var rad = this.rad;
            var metersPerDegree = this.metersPerDegree;
            var x = pLnglat.x / metersPerDegree;
            var y = pLnglat.y;
            var c;

            if (y === 0) {
                c = 0;
            } else {
                c = y / metersPerDegree;
                c = (2 * Math.atan(Math.exp(c * rad)) - Math.PI / 2) / rad;
            }

            if (Math.abs(Math.abs(x) - 180) < delta) {
                x = sign(x) * 180;
            }

            if (Math.abs(Math.abs(c) - this.maxLatitude) < delta) {
                c = sign(c) * this.maxLatitude;
            }

            var rx = wrap(x, -180, 180);
            var ry = wrap(c, -this.maxLatitude, this.maxLatitude);

            if (out) {
                out.x = rx;
                out.y = ry;
                return out;
            }

            return new Coordinate(rx, ry);
        }
    }, WGS84Sphere);

    var PROJ4326 = extend({}, Common, {
        code: 'EPSG:4326',
        project: function project(p, out) {
            if (out) {
                out.x = p.x;
                out.y = p.y;
                return out;
            }

            return new Coordinate(p);
        },
        unproject: function unproject(p, out) {
            if (out) {
                out.x = p.x;
                out.y = p.y;
                return out;
            }

            return new Coordinate(p);
        }
    }, WGS84Sphere);

    var Projection_EPSG4490 = extend({}, PROJ4326, {
        code: 'EPSG:4490'
    });

    var Projection_Baidu = extend({}, Common, {
        code: 'BAIDU',
        project: function project(p, out) {
            return this.convertLL2MC(p, out);
        },
        unproject: function unproject(p, out) {
            return this.convertMC2LL(p, out);
        }
    }, BaiduSphere, {
        EARTHRADIUS: 6370996.81,
        MCBAND: [12890594.86, 8362377.87, 5591021, 3481989.83, 1678043.12, 0],
        LLBAND: [75, 60, 45, 30, 15, 0],
        MC2LL: [
            [1.410526172116255e-8, 0.00000898305509648872, -1.9939833816331, 200.9824383106796, -187.2403703815547, 91.6087516669843, -23.38765649603339, 2.57121317296198, -0.03801003308653, 17337981.2],
            [-7.435856389565537e-9, 0.000008983055097726239, -0.78625201886289, 96.32687599759846, -1.85204757529826, -59.36935905485877, 47.40033549296737, -16.50741931063887, 2.28786674699375, 10260144.86],
            [-3.030883460898826e-8, 0.00000898305509983578, 0.30071316287616, 59.74293618442277, 7.357984074871, -25.38371002664745, 13.45380521110908, -3.29883767235584, 0.32710905363475, 6856817.37],
            [-1.981981304930552e-8, 0.000008983055099779535, 0.03278182852591, 40.31678527705744, 0.65659298677277, -4.44255534477492, 0.85341911805263, 0.12923347998204, -0.04625736007561, 4482777.06],
            [3.09191371068437e-9, 0.000008983055096812155, 0.00006995724062, 23.10934304144901, -0.00023663490511, -0.6321817810242, -0.00663494467273, 0.03430082397953, -0.00466043876332, 2555164.4],
            [2.890871144776878e-9, 0.000008983055095805407, -3.068298e-8, 7.47137025468032, -0.00000353937994, -0.02145144861037, -0.00001234426596, 0.00010322952773, -0.00000323890364, 826088.5]
        ],
        LL2MC: [
            [-0.0015702102444, 111320.7020616939, 1704480524535203, -10338987376042340, 26112667856603880, -35149669176653700, 26595700718403920, -10725012454188240, 1800819912950474, 82.5],
            [0.0008277824516172526, 111320.7020463578, 647795574.6671607, -4082003173.641316, 10774905663.51142, -15171875531.51559, 12053065338.62167, -5124939663.577472, 913311935.9512032, 67.5],
            [0.00337398766765, 111320.7020202162, 4481351.045890365, -23393751.19931662, 79682215.47186455, -115964993.2797253, 97236711.15602145, -43661946.33752821, 8477230.501135234, 52.5],
            [0.00220636496208, 111320.7020209128, 51751.86112841131, 3796837.749470245, 992013.7397791013, -1221952.21711287, 1340652.697009075, -620943.6990984312, 144416.9293806241, 37.5],
            [-0.0003441963504368392, 111320.7020576856, 278.2353980772752, 2485758.690035394, 6070.750963243378, 54821.18345352118, 9540.606633304236, -2710.55326746645, 1405.483844121726, 22.5],
            [-0.0003218135878613132, 111320.7020701615, 0.00369383431289, 823725.6402795718, 0.46104986909093, 2351.343141331292, 1.58060784298199, 8.77738589078284, 0.37238884252424, 7.45]
        ],
        convertMC2LL: function convertMC2LL(cB, out) {
            var cE;

            for (var cD = 0, len = this.MCBAND.length; cD < len; cD++) {
                if (Math.abs(cB.y) >= this.MCBAND[cD]) {
                    cE = this.MC2LL[cD];
                    break;
                }
            }

            var T = this.convertor(cB, cE, out);
            return T;
        },
        convertLL2MC: function convertLL2MC(T, out) {
            var cD, cC, len;
            T.x = this.getLoop(T.x, -180, 180);
            T.y = this.getRange(T.y, -74, 74);
            var cB = new Coordinate(T.x, T.y);

            for (cC = 0, len = this.LLBAND.length; cC < len; cC++) {
                if (cB.y >= this.LLBAND[cC]) {
                    cD = this.LL2MC[cC];
                    break;
                }
            }

            if (!cD) {
                for (cC = this.LLBAND.length - 1; cC >= 0; cC--) {
                    if (cB.y <= -this.LLBAND[cC]) {
                        cD = this.LL2MC[cC];
                        break;
                    }
                }
            }

            var cE = this.convertor(T, cD, out);
            return cE;
        },
        convertor: function convertor(cC, cD, out) {
            if (!cC || !cD) {
                return null;
            }

            var T = cD[0] + cD[1] * Math.abs(cC.x);
            var cB = Math.abs(cC.y) / cD[9];
            var cE = cD[2] + cD[3] * cB + cD[4] * cB * cB + cD[5] * cB * cB * cB + cD[6] * cB * cB * cB * cB + cD[7] * cB * cB * cB * cB * cB + cD[8] * cB * cB * cB * cB * cB * cB;
            T *= cC.x < 0 ? -1 : 1;
            cE *= cC.y < 0 ? -1 : 1;

            if (out) {
                out.x = T;
                out.y = cE;
                return out;
            }

            return new Coordinate(T, cE);
        },
        toRadians: function toRadians(T) {
            return Math.PI * T / 180;
        },
        toDegrees: function toDegrees(T) {
            return 180 * T / Math.PI;
        },
        getRange: function getRange(cC, cB, T) {
            if (cB != null) {
                cC = Math.max(cC, cB);
            }

            if (T != null) {
                cC = Math.min(cC, T);
            }

            return cC;
        },
        getLoop: function getLoop(cC, cB, T) {
            if (cC === Infinity) {
                return T;
            } else if (cC === -Infinity) {
                return cB;
            }

            while (cC > T) {
                cC -= T - cB;
            }

            while (cC < cB) {
                cC += T - cB;
            }

            return cC;
        }
    });

    var Projection_IDENTITY = extend({}, Common, {
        code: 'IDENTITY',
        project: function project(p, out) {
            if (out) {
                out.x = p.x;
                out.y = p.y;
                return out;
            }

            return p.copy();
        },
        unproject: function unproject(p, out) {
            if (out) {
                out.x = p.x;
                out.y = p.y;
                return out;
            }

            return p.copy();
        }
    }, Identity);

    var DEFAULT$1 = EPSG3857;

    var projections = /*#__PURE__*/ Object.freeze({
        EPSG3857: EPSG3857,
        DEFAULT: DEFAULT$1,
        EPSG4326: PROJ4326,
        EPSG4490: Projection_EPSG4490,
        BAIDU: Projection_Baidu,
        IDENTITY: Projection_IDENTITY,
        Common: Common
    });

    var Renderable = (function(Base) {
        return function(_Base) {
            _inheritsLoose(_class, _Base);

            function _class() {
                return _Base.apply(this, arguments) || this;
            }

            _class.registerRenderer = function registerRenderer(name, clazz) {
                var proto = this.prototype;
                var parentProto = Object.getPrototypeOf(proto);

                if (!proto._rendererClasses || proto._rendererClasses === parentProto._rendererClasses) {
                    proto._rendererClasses = proto._rendererClasses ? Object.create(proto._rendererClasses) : {};
                }

                proto._rendererClasses[name.toLowerCase()] = clazz;
                return this;
            };

            _class.getRendererClass = function getRendererClass(name) {
                var proto = this.prototype;

                if (!proto._rendererClasses) {
                    return null;
                }

                return proto._rendererClasses[name.toLowerCase()];
            };

            return _class;
        }(Base);
    });

    var CanvasRenderer = function(_Class) {
        _inheritsLoose(CanvasRenderer, _Class);

        function CanvasRenderer(layer) {
            var _this;

            _this = _Class.call(this) || this;
            _this.layer = layer;
            _this._painted = false;
            _this._drawTime = 0;

            _this.setToRedraw();

            return _this;
        }

        var _proto = CanvasRenderer.prototype;

        _proto.render = function render(framestamp) {
            this.prepareRender();

            if (!this.getMap() || !this.layer.isVisible()) {
                return;
            }

            if (!this.resources) {
                this.resources = new ResourceCache();
            }

            this.checkAndDraw(this._tryToDraw, framestamp);
        };

        _proto.checkAndDraw = function checkAndDraw(drawFn) {
            var _this2 = this;

            for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
                args[_key - 1] = arguments[_key];
            }

            if (this.checkResources) {
                var resources = this.checkResources();

                if (resources.length > 0) {
                    this._loadingResource = true;
                    this.loadResources(resources).then(function() {
                        _this2._loadingResource = false;

                        if (_this2.layer) {
                            _this2.layer.fire('resourceload');

                            _this2.setToRedraw();
                        }
                    });
                } else {
                    drawFn.call.apply(drawFn, [this].concat(args));
                }
            } else {
                drawFn.call.apply(drawFn, [this].concat(args));
            }
        };

        _proto.testIfNeedRedraw = function testIfNeedRedraw() {
            var map = this.getMap();

            if (this._loadingResource) {
                return false;
            }

            if (this._toRedraw) {
                return true;
            }

            if (map.isInteracting() && !this.drawOnInteracting) {
                return false;
            }

            if (this.needToRedraw()) {
                return true;
            }

            return false;
        };

        _proto.needToRedraw = function needToRedraw() {
            var map = this.getMap();

            if (map.isInteracting() || map.getRenderer().isViewChanged()) {
                return !(!map.getPitch() && map.isMoving() && !map.isZooming() && !map.isRotating() && !this.layer.options['forceRenderOnMoving']);
            }

            return false;
        };

        _proto.onSkipDrawOnInteracting = function onSkipDrawOnInteracting() {};

        _proto.isLoadingResource = function isLoadingResource() {
            return this._loadingResource;
        };

        _proto.isRenderComplete = function isRenderComplete() {
            return !!this._renderComplete;
        };

        _proto.mustRenderOnInteracting = function mustRenderOnInteracting() {
            return !this._painted;
        };

        _proto.setToRedraw = function setToRedraw() {
            this._toRedraw = true;
            return this;
        };

        _proto.setCanvasUpdated = function setCanvasUpdated() {
            this._canvasUpdated = true;
            return this;
        };

        _proto.isCanvasUpdated = function isCanvasUpdated() {
            return !!this._canvasUpdated;
        };

        _proto.remove = function remove() {
            this.onRemove();
            delete this._loadingResource;
            delete this.southWest;
            delete this.canvas;
            delete this.context;
            delete this.canvasExtent2D;
            delete this._extent2D;
            delete this.resources;
            delete this.layer;
        };

        _proto.onRemove = function onRemove() {};

        _proto.onAdd = function onAdd() {};

        _proto.getMap = function getMap() {
            if (!this.layer) {
                return null;
            }

            return this.layer.getMap();
        };

        _proto.getCanvasImage = function getCanvasImage() {
            var map = this.getMap();
            this._canvasUpdated = false;

            if (this._renderZoom !== map.getZoom() || !this.canvas || !this._extent2D) {
                return null;
            }

            if (this.isBlank()) {
                return null;
            }

            if (this.layer.isEmpty && this.layer.isEmpty()) {
                return null;
            }

            var containerPoint = map._pointToContainerPoint(this.southWest)._add(0, -map.height);

            return {
                'image': this.canvas,
                'layer': this.layer,
                'point': containerPoint
            };
        };

        _proto.clear = function clear() {
            this.clearCanvas();
        };

        _proto.isBlank = function isBlank() {
            if (!this._painted) {
                return true;
            }

            return false;
        };

        _proto.show = function show() {
            this.setToRedraw();
        };

        _proto.hide = function hide() {
            this.clear();
            this.setToRedraw();
        };

        _proto.setZIndex = function setZIndex() {
            this.setToRedraw();
        };

        _proto.hitDetect = function hitDetect(point) {
            if (!this.context || this.layer.isEmpty && this.layer.isEmpty() || this.isBlank() || this._errorThrown) {
                return false;
            }

            var map = this.getMap();
            var r = map.getDevicePixelRatio();
            var size = map.getSize();

            if (point.x < 0 || point.x > size['width'] * r || point.y < 0 || point.y > size['height'] * r) {
                return false;
            }

            try {
                var imgData = this.context.getImageData(r * point.x, r * point.y, 1, 1).data;

                if (imgData[3] > 0) {
                    return true;
                }
            } catch (error) {
                if (!this._errorThrown) {
                    if (console) {
                        console.warn('hit detect failed with tainted canvas, some geometries have external resources in another domain:\n', error);
                    }

                    this._errorThrown = true;
                }

                return false;
            }

            return false;
        };

        _proto.loadResources = function loadResources(resourceUrls) {
            if (!this.resources) {
                this.resources = new ResourceCache();
            }

            var resources = this.resources,
                promises = [];

            if (isArrayHasData(resourceUrls)) {
                var cache = {};

                for (var i = resourceUrls.length - 1; i >= 0; i--) {
                    var url = resourceUrls[i];

                    if (!url || !url.length || cache[url.join('-')]) {
                        continue;
                    }

                    cache[url.join('-')] = 1;

                    if (!resources.isResourceLoaded(url, true)) {
                        promises.push(new Promise$1(this._promiseResource(url)));
                    }
                }
            }

            return Promise$1.all(promises);
        };

        _proto.prepareRender = function prepareRender() {
            delete this._renderComplete;
            var map = this.getMap();
            this._renderZoom = map.getZoom();
            this.canvasExtent2D = this._extent2D = map._get2DExtent();
            this.southWest = map._containerPointToPoint(new Point(0, map.height));
        };

        _proto.createCanvas = function createCanvas() {
            if (this.canvas) {
                return;
            }

            var map = this.getMap();
            var size = map.getSize();
            var r = map.getDevicePixelRatio(),
                w = r * size.width,
                h = r * size.height;

            if (this.layer._canvas) {
                var canvas = this.layer._canvas;
                canvas.width = w;
                canvas.height = h;

                if (canvas.style) {
                    canvas.style.width = size.width + 'px';
                    canvas.style.height = size.height + 'px';
                }

                this.canvas = this.layer._canvas;
            } else {
                this.canvas = Canvas.createCanvas(w, h, map.CanvasClass);
            }

            this.onCanvasCreate();
        };

        _proto.onCanvasCreate = function onCanvasCreate() {};

        _proto.createContext = function createContext() {
            if (this.gl && this.gl.canvas === this.canvas || this.context) {
                return;
            }

            this.context = this.canvas.getContext('2d');

            if (!this.context) {
                return;
            }

            if (this.layer.options['globalCompositeOperation']) {
                this.context.globalCompositeOperation = this.layer.options['globalCompositeOperation'];
            }

            var dpr = this.getMap().getDevicePixelRatio();

            if (dpr !== 1) {
                this.context.scale(dpr, dpr);
            }
        };

        _proto.resetCanvasTransform = function resetCanvasTransform() {
            if (!this.context) {
                return;
            }

            var dpr = this.getMap().getDevicePixelRatio();
            this.context.setTransform(dpr, 0, 0, dpr, 0, 0);
        };

        _proto.resizeCanvas = function resizeCanvas(canvasSize) {
            var canvas = this.canvas;

            if (!canvas) {
                return;
            }

            var size = canvasSize || this.getMap().getSize();
            var r = this.getMap().getDevicePixelRatio();

            if (canvas.width === r * size.width && canvas.height === r * size.height) {
                return;
            }

            canvas.height = r * size.height;
            canvas.width = r * size.width;

            if (r !== 1 && this.context) {
                this.context.scale(r, r);
            }

            if (this.layer._canvas && canvas.style) {
                canvas.style.width = size.width + 'px';
                canvas.style.height = size.height + 'px';
            }
        };

        _proto.clearCanvas = function clearCanvas() {
            if (!this.context) {
                return;
            }

            Canvas.clearRect(this.context, 0, 0, this.canvas.width, this.canvas.height);
        };

        _proto.prepareCanvas = function prepareCanvas() {
            if (!this.canvas) {
                this.createCanvas();
                this.createContext();
                this.layer.onCanvasCreate();
                this.layer.fire('canvascreate', {
                    'context': this.context,
                    'gl': this.gl
                });
            } else {
                this.resetCanvasTransform();
                this.clearCanvas();
                this.resizeCanvas();
            }

            delete this._maskExtent;
            var mask = this.layer.getMask();

            if (!mask) {
                this.layer.fire('renderstart', {
                    'context': this.context,
                    'gl': this.gl
                });
                return null;
            }

            var maskExtent2D = this._maskExtent = mask._getMaskPainter().get2DExtent();

            if (!maskExtent2D.intersects(this._extent2D)) {
                this.layer.fire('renderstart', {
                    'context': this.context,
                    'gl': this.gl
                });
                return maskExtent2D;
            }

            this.layer.fire('renderstart', {
                'context': this.context,
                'gl': this.gl
            });
            return maskExtent2D;
        };

        _proto.clipCanvas = function clipCanvas(context) {
            var mask = this.layer.getMask();

            if (!mask) {
                return false;
            }

            var old = this.southWest;
            var map = this.getMap();
            this.southWest = map._containerPointToPoint(new Point(0, map.height));
            context.save();
            var dpr = map.getDevicePixelRatio();

            if (dpr !== 1) {
                context.save();
                context.scale(dpr, dpr);
            }

            if (mask.getGeometries) {
                context.isMultiClip = true;
                var masks = mask.getGeometries() || [];
                context.beginPath();
                masks.forEach(function(_mask) {
                    var painter = _mask._getMaskPainter();

                    painter.paint(null, context);
                });
                context.stroke();
                delete context.isMultiClip;
            } else {
                var painter = mask._getMaskPainter();

                painter.paint(null, context);
            }

            if (dpr !== 1) {
                context.restore();
            }

            context.clip();
            this.southWest = old;
            return true;
        };

        _proto.getViewExtent = function getViewExtent() {
            return {
                'extent': this._extent2D,
                'maskExtent': this._maskExtent,
                'zoom': this._renderZoom,
                'southWest': this.southWest
            };
        };

        _proto.completeRender = function completeRender() {
            if (this.getMap()) {
                this._renderComplete = true;
                this.layer.fire('renderend', {
                    'context': this.context,
                    'gl': this.gl
                });
                this.setCanvasUpdated();
            }
        };

        _proto.getEvents = function getEvents() {
            return {
                '_zoomstart': this.onZoomStart,
                '_zooming': this.onZooming,
                '_zoomend': this.onZoomEnd,
                '_resize': this.onResize,
                '_movestart': this.onMoveStart,
                '_moving': this.onMoving,
                '_moveend': this.onMoveEnd,
                '_dragrotatestart': this.onDragRotateStart,
                '_dragrotating': this.onDragRotating,
                '_dragrotateend': this.onDragRotateEnd,
                '_spatialreferencechange': this.onSpatialReferenceChange
            };
        };

        _proto.onZoomStart = function onZoomStart() {};

        _proto.onZoomEnd = function onZoomEnd() {
            this.setToRedraw();
        };

        _proto.onZooming = function onZooming() {};

        _proto.onMoveStart = function onMoveStart() {};

        _proto.onMoving = function onMoving() {};

        _proto.onMoveEnd = function onMoveEnd() {
            this.setToRedraw();
        };

        _proto.onResize = function onResize() {
            delete this._extent2D;
            this.resizeCanvas();
            this.setToRedraw();
        };

        _proto.onDragRotateStart = function onDragRotateStart() {};

        _proto.onDragRotating = function onDragRotating() {};

        _proto.onDragRotateEnd = function onDragRotateEnd() {
            this.setToRedraw();
        };

        _proto.onSpatialReferenceChange = function onSpatialReferenceChange() {};

        _proto.getDrawTime = function getDrawTime() {
            return this._drawTime;
        };

        _proto._tryToDraw = function _tryToDraw(framestamp) {
            this._toRedraw = false;

            if (!this.canvas && this.layer.isEmpty && this.layer.isEmpty()) {
                this._renderComplete = true;
                return;
            }

            this._drawAndRecord(framestamp);
        };

        _proto._drawAndRecord = function _drawAndRecord(framestamp) {
            if (!this.getMap()) {
                return;
            }

            var painted = this._painted;
            this._painted = true;
            var t = now();
            this.draw(framestamp);
            t = now() - t;
            this._drawTime = painted ? t : t / 2;

            if (painted && this.layer && this.layer.options['logDrawTime']) {
                console.log(this.layer.getId(), 'frameTimeStamp:', framestamp, 'drawTime:', this._drawTime);
            }
        };

        _proto._promiseResource = function _promiseResource(url) {
            var me = this,
                resources = this.resources,
                crossOrigin = this.layer.options['crossOrigin'];
            return function(resolve) {
                if (resources.isResourceLoaded(url, true)) {
                    resolve(url);
                    return;
                }

                var img = new Image();

                if (!isNil(crossOrigin)) {
                    img['crossOrigin'] = crossOrigin;
                }

                if (isSVG(url[0]) && !IS_NODE) {
                    if (url[1]) {
                        url[1] *= 2;
                    }

                    if (url[2]) {
                        url[2] *= 2;
                    }
                }

                img.onload = function() {
                    me._cacheResource(url, img);

                    resolve(url);
                };

                img.onabort = function(err) {
                    if (console) {
                        console.warn('image loading aborted: ' + url[0]);
                    }

                    if (err) {
                        if (console) {
                            console.warn(err);
                        }
                    }

                    resolve(url);
                };

                img.onerror = function(err) {
                    if (err && typeof console !== 'undefined') {
                        console.warn(err);
                    }

                    resources.markErrorResource(url);
                    resolve(url);
                };

                loadImage(img, url);
            };
        };

        _proto._cacheResource = function _cacheResource(url, img) {
            if (!this.layer || !this.resources) {
                return;
            }

            var w = url[1],
                h = url[2];

            if (this.layer.options['cacheSvgOnCanvas'] && isSVG(url[0]) === 1 && (Browser$1.edge || Browser$1.ie)) {
                if (isNil(w)) {
                    w = img.width || this.layer.options['defaultIconSize'][0];
                }

                if (isNil(h)) {
                    h = img.height || this.layer.options['defaultIconSize'][1];
                }

                var canvas = Canvas.createCanvas(w, h);
                Canvas.image(canvas.getContext('2d'), img, 0, 0, w, h);
                img = canvas;
            }

            this.resources.addResource(url, img);
        };

        return CanvasRenderer;
    }(Class);
    var ResourceCache = function() {
        function ResourceCache() {
            this.resources = {};
            this._errors = {};
        }

        var _proto2 = ResourceCache.prototype;

        _proto2.addResource = function addResource(url, img) {
            this.resources[url[0]] = {
                image: img,
                width: +url[1],
                height: +url[2]
            };
        };

        _proto2.isResourceLoaded = function isResourceLoaded(url, checkSVG) {
            if (!url) {
                return false;
            }

            var imgUrl = this._getImgUrl(url);

            if (this._errors[imgUrl]) {
                return true;
            }

            var img = this.resources[imgUrl];

            if (!img) {
                return false;
            }

            if (checkSVG && isSVG(url[0]) && (+url[1] > img.width || +url[2] > img.height)) {
                return false;
            }

            return true;
        };

        _proto2.getImage = function getImage(url) {
            var imgUrl = this._getImgUrl(url);

            if (!this.isResourceLoaded(url) || this._errors[imgUrl]) {
                return null;
            }

            return this.resources[imgUrl].image;
        };

        _proto2.markErrorResource = function markErrorResource(url) {
            this._errors[this._getImgUrl(url)] = 1;
        };

        _proto2.merge = function merge(res) {
            if (!res) {
                return this;
            }

            for (var p in res.resources) {
                var img = res.resources[p];
                this.addResource([p, img.width, img.height], img.image);
            }

            return this;
        };

        _proto2.forEach = function forEach(fn) {
            if (!this.resources) {
                return this;
            }

            for (var p in this.resources) {
                if (hasOwn(this.resources, p)) {
                    fn(p, this.resources[p]);
                }
            }

            return this;
        };

        _proto2._getImgUrl = function _getImgUrl(url) {
            if (!Array.isArray(url)) {
                return url;
            }

            return url[0];
        };

        return ResourceCache;
    }();

    function clipLine(points, bounds, round, noCut) {
        var parts = [];
        var k = 0,
            segment;

        for (var j = 0, l = points.length; j < l - 1; j++) {
            segment = clipSegment(points[j], points[j + 1], bounds, j, round, noCut);

            if (!segment) {
                continue;
            }

            parts[k] = parts[k] || [];
            parts[k].push({
                'point': segment[0],
                'index': j
            });

            if (segment[1] !== points[j + 1] || j === l - 2) {
                parts[k].push({
                    'point': segment[1],
                    'index': j + 1
                });
                k++;
            }
        }

        return parts;
    }

    var _lastCode;

    function clipSegment(a, b, bounds, useLastCode, round, noCut) {
        var codeA = useLastCode ? _lastCode : _getBitCode(a, bounds),
            codeB = _getBitCode(b, bounds),
            codeOut,
            p,
            newCode;

        _lastCode = codeB;

        while (true) {
            if (!(codeA | codeB)) {
                return [a, b];
            }

            if (codeA & codeB) {
                return false;
            }

            if (noCut) {
                return [a, b];
            }

            codeOut = codeA || codeB;
            p = _getEdgeIntersection(a, b, codeOut, bounds, round);
            newCode = _getBitCode(p, bounds);

            if (codeOut === codeA) {
                a = p;
                codeA = newCode;
            } else {
                b = p;
                codeB = newCode;
            }
        }
    }

    function clipPolygon(points, bounds, round) {
        var edges = [1, 4, 2, 8];
        var clippedPoints, i, j, k, a, b, len, edge, p;

        for (i = 0, len = points.length; i < len; i++) {
            points[i]._code = _getBitCode(points[i], bounds);
        }

        for (k = 0; k < 4; k++) {
            edge = edges[k];
            clippedPoints = [];

            for (i = 0, len = points.length, j = len - 1; i < len; j = i++) {
                a = points[i];
                b = points[j];

                if (!(a._code & edge)) {
                    if (b._code & edge) {
                        p = _getEdgeIntersection(b, a, edge, bounds, round);
                        p._code = _getBitCode(p, bounds);
                        clippedPoints.push(p);
                    }

                    clippedPoints.push(a);
                } else if (!(b._code & edge)) {
                    p = _getEdgeIntersection(b, a, edge, bounds, round);
                    p._code = _getBitCode(p, bounds);
                    clippedPoints.push(p);
                }
            }

            points = clippedPoints;
        }

        return points;
    }

    function _getEdgeIntersection(a, b, code, bounds, round) {
        var dx = b.x - a.x,
            dy = b.y - a.y,
            min = bounds.getMin(),
            max = bounds.getMax();
        var x, y;

        if (code & 8) {
            x = a.x + dx * (max.y - a.y) / dy;
            y = max.y;
        } else if (code & 4) {
            x = a.x + dx * (min.y - a.y) / dy;
            y = min.y;
        } else if (code & 2) {
            x = max.x;
            y = a.y + dy * (max.x - a.x) / dx;
        } else if (code & 1) {
            x = min.x;
            y = a.y + dy * (min.x - a.x) / dx;
        }

        var p = new Point(x, y);

        if (round) {
            p._round();
        }

        return p;
    }

    function _getBitCode(p, bounds) {
        var code = 0;

        if (p.x < bounds.getMin().x) {
            code |= 1;
        } else if (p.x > bounds.getMax().x) {
            code |= 2;
        }

        if (p.y < bounds.getMin().y) {
            code |= 4;
        } else if (p.y > bounds.getMax().y) {
            code |= 8;
        }

        return code;
    }

    function withInEllipse(point, center, southeast, tolerance) {
        point = new Point(point);
        var a = Math.abs(southeast.x - center.x),
            b = Math.abs(southeast.y - center.y),
            c = Math.sqrt(Math.abs(a * a - b * b)),
            xfocus = a >= b;
        var f1, f2, d;

        if (xfocus) {
            f1 = new Point(center.x - c, center.y);
            f2 = new Point(center.x + c, center.y);
            d = a * 2;
        } else {
            f1 = new Point(center.x, center.y - c);
            f2 = new Point(center.x, center.y + c);
            d = b * 2;
        }

        return point.distanceTo(f1) + point.distanceTo(f2) <= d + 2 * tolerance;
    }

    var Symbolizer = function() {
        function Symbolizer() {}

        var _proto = Symbolizer.prototype;

        _proto.getMap = function getMap() {
            return this.geometry.getMap();
        };

        _proto.getPainter = function getPainter() {
            return this.painter;
        };

        _proto.isDynamicSize = function isDynamicSize() {
            return false;
        };

        Symbolizer.testColor = function testColor(prop) {
            if (!prop || !isString(prop)) {
                return false;
            }

            if (COLOR_PROPERTIES.indexOf(prop) >= 0) {
                return true;
            }

            return false;
        };

        return Symbolizer;
    }();

    var CanvasSymbolizer = function(_Symbolizer) {
        _inheritsLoose(CanvasSymbolizer, _Symbolizer);

        function CanvasSymbolizer() {
            return _Symbolizer.apply(this, arguments) || this;
        }

        var _proto = CanvasSymbolizer.prototype;

        _proto._prepareContext = function _prepareContext(ctx) {
            if (isNumber(this.symbol['opacity'])) {
                if (ctx.globalAlpha !== this.symbol['opacity']) {
                    ctx.globalAlpha = this.symbol['opacity'];
                }
            } else if (ctx.globalAlpha !== 1) {
                ctx.globalAlpha = 1;
            }
        };

        _proto.prepareCanvas = function prepareCanvas(ctx, style, resources) {
            Canvas.prepareCanvas(ctx, style, resources, this.getPainter().isHitTesting());
        };

        _proto.remove = function remove() {};

        _proto.setZIndex = function setZIndex() {};

        _proto.show = function show() {};

        _proto.hide = function hide() {};

        _proto._defineStyle = function _defineStyle(style) {
            return function() {
                var _this = this;

                var arr = [],
                    prop = {};
                return loadFunctionTypes(style, function() {
                    var map = _this.getMap();

                    return set$1(arr, map.getZoom(), extend({}, _this.geometry.getProperties(), setProp(prop, map.getBearing(), map.getPitch(), map.getZoom())));
                });
            }.bind(this)();
        };

        return CanvasSymbolizer;
    }(Symbolizer);

    function set$1(arr, a0, a1) {
        arr[0] = a0;
        arr[1] = a1;
        return arr;
    }

    function setProp(prop, b, p, z) {
        prop['{bearing}'] = b;
        prop['{pitch}'] = p;
        prop['{zoom}'] = z;
        return prop;
    }

    var TEMP_POINT0$1 = new Point(0, 0);
    var TEMP_POINT1 = new Point(0, 0);

    var PointSymbolizer = function(_CanvasSymbolizer) {
        _inheritsLoose(PointSymbolizer, _CanvasSymbolizer);

        function PointSymbolizer(symbol, geometry, painter) {
            var _this;

            _this = _CanvasSymbolizer.call(this) || this;
            _this.symbol = symbol;
            _this.geometry = geometry;
            _this.painter = painter;
            return _this;
        }

        var _proto = PointSymbolizer.prototype;

        _proto.get2DExtent = function get2DExtent() {
            var map = this.getMap();
            var glZoom = map.getGLZoom();
            var extent = new PointExtent();

            var renderPoints = this._getRenderPoints()[0];

            for (var i = renderPoints.length - 1; i >= 0; i--) {
                if (renderPoints[i]) {
                    extent._combine(map._pointToPoint(renderPoints[i], glZoom));
                }
            }

            return extent;
        };

        _proto.isDynamicSize = function isDynamicSize() {
            var symbol = this.symbol;
            return isFunctionDefinition(symbol['markerWidth']) || isFunctionDefinition(symbol['markerHeight']) || isFunctionDefinition(symbol['textSize']);
        };

        _proto._rotateExtent = function _rotateExtent(fixedExtent, angle) {
            return fixedExtent.convertTo(function(p) {
                return p._rotate(angle);
            });
        };

        _proto._getRenderPoints = function _getRenderPoints() {
            var painter = this.getPainter();
            var placement = painter.isSpriting() ? 'center' : this.getPlacement();
            return this.getPainter().getRenderPoints(placement);
        };

        _proto._getRenderContainerPoints = function _getRenderContainerPoints(ignoreAltitude) {
            var painter = this.getPainter(),
                points = this._getRenderPoints()[0];

            if (painter.isSpriting()) {
                return points;
            }

            var dxdy = this.getDxDy();

            var cpoints = this.painter._pointContainerPoints(points, dxdy.x, dxdy.y, ignoreAltitude, true, this.getPlacement());

            if (!cpoints || !Array.isArray(cpoints[0])) {
                return cpoints;
            }

            var flat = [];

            for (var i = 0, l = cpoints.length; i < l; i++) {
                for (var ii = 0, ll = cpoints[i].length; ii < ll; ii++) {
                    flat.push(cpoints[i][ii]);
                }
            }

            return flat;
        };

        _proto._getRotationAt = function _getRotationAt(i) {
            var r = this.getRotation();

            if (!r) {
                r = 0;
            }

            var rotations = this._getRenderPoints()[1];

            if (!rotations || !rotations[i]) {
                return r;
            }

            var map = this.getMap();
            var p0 = rotations[i][0],
                p1 = rotations[i][1];

            if (map.isTransforming()) {
                var maxZoom = map.getGLZoom();
                p0 = map._pointToContainerPoint(rotations[i][0], maxZoom, 0, TEMP_POINT0$1);
                p1 = map._pointToContainerPoint(rotations[i][1], maxZoom, 0, TEMP_POINT1);
                return r + computeDegree(p0.x, p0.y, p1.x, p1.y);
            } else {
                return r + -computeDegree(p0.x, p0.y, p1.x, p1.y);
            }
        };

        _proto._rotate = function _rotate(ctx, origin, rotation) {
            if (rotation) {
                var dxdy = this.getDxDy();
                var p = origin.sub(dxdy);
                ctx.save();
                ctx.translate(p.x, p.y);
                ctx.rotate(rotation);
                return this.getDxDy();
            }

            return null;
        };

        return PointSymbolizer;
    }(CanvasSymbolizer);

    var VectorMarkerSymbolizer = function(_PointSymbolizer) {
        _inheritsLoose(VectorMarkerSymbolizer, _PointSymbolizer);

        VectorMarkerSymbolizer.test = function test(symbol) {
            if (!symbol) {
                return false;
            }

            if (isNil(symbol['markerFile']) && !isNil(symbol['markerType']) && symbol['markerType'] !== 'path') {
                return true;
            }

            return false;
        };

        function VectorMarkerSymbolizer(symbol, geometry, painter) {
            var _this;

            _this = _PointSymbolizer.call(this, symbol, geometry, painter) || this;
            _this._dynamic = hasFunctionDefinition(symbol);
            _this.style = _this._defineStyle(_this.translate());
            _this.strokeAndFill = _this._defineStyle(VectorMarkerSymbolizer.translateLineAndFill(_this.style));
            var lineWidth = _this.strokeAndFill['lineWidth'];

            if (lineWidth % 2 === 0) {
                _this.padding = 2;
            } else {
                _this.padding = 1.5;
            }

            return _this;
        }

        var _proto = VectorMarkerSymbolizer.prototype;

        _proto.symbolize = function symbolize(ctx, resources) {
            var style = this.style;

            if (!this.painter.isHitTesting() && (style['markerWidth'] === 0 || style['markerHeight'] === 0 || style['polygonOpacity'] === 0 && style['lineOpacity'] === 0)) {
                return;
            }

            var cookedPoints = this._getRenderContainerPoints();

            if (!isArrayHasData(cookedPoints)) {
                return;
            }

            this._prepareContext(ctx);

            if (this.getPainter().isSpriting() || this.geometry.getLayer().getMask() === this.geometry || this._dynamic || this.geometry.getLayer().options['cacheVectorOnCanvas'] === false) {
                this._drawMarkers(ctx, cookedPoints, resources);
            } else {
                this._drawMarkersWithCache(ctx, cookedPoints, resources);
            }
        };

        _proto.getDxDy = function getDxDy() {
            var s = this.style;
            var dx = s['markerDx'],
                dy = s['markerDy'];
            return new Point(dx, dy);
        };

        _proto._drawMarkers = function _drawMarkers(ctx, cookedPoints, resources) {
            var strokeAndFill = this.strokeAndFill;
            var gradient = isGradient(strokeAndFill['lineColor']) || isGradient(strokeAndFill['polygonFill']);

            if (!gradient) {
                this.prepareCanvas(ctx, strokeAndFill, resources);
            }

            for (var i = cookedPoints.length - 1; i >= 0; i--) {
                var point = cookedPoints[i];

                var origin = this._rotate(ctx, point, this._getRotationAt(i));

                if (origin) {
                    point = origin;
                }

                this._drawVectorMarker(ctx, point, resources);

                if (origin) {
                    ctx.restore();
                }
            }
        };

        _proto._drawMarkersWithCache = function _drawMarkersWithCache(ctx, cookedPoints, resources) {
            var stamp = this._stampSymbol();

            var image = resources.getImage(stamp);

            if (!image) {
                image = this._createMarkerImage(ctx, resources);
                resources.addResource([stamp, image.width, image.height], image);
            }

            var anchor = this._getAnchor(image.width, image.height);

            for (var i = cookedPoints.length - 1; i >= 0; i--) {
                var point = cookedPoints[i];

                var origin = this._rotate(ctx, point, this._getRotationAt(i));

                if (origin) {
                    point = origin;
                }

                Canvas.image(ctx, image, point.x + anchor.x, point.y + anchor.y);

                if (origin) {
                    ctx.restore();
                }
            }
        };

        _proto._calMarkerSize = function _calMarkerSize() {
            if (!this._size) {
                var lineWidth = this.strokeAndFill['lineWidth'],
                    shadow = 2 * (this.symbol['shadowBlur'] || 0),
                    w = Math.round(this.style['markerWidth'] + lineWidth + 2 * shadow + this.padding * 2),
                    h = Math.round(this.style['markerHeight'] + lineWidth + 2 * shadow + this.padding * 2);

                if (isFunctionDefinition(this.symbol['markerWidth']) || isFunctionDefinition(this.symbol['markerHeight'])) {
                    return [w, h];
                }

                this._size = [w, h];
            }

            return this._size;
        };

        _proto._createMarkerImage = function _createMarkerImage(ctx, resources) {
            var canvasClass = ctx.canvas.constructor,
                size = this._calMarkerSize(),
                canvas = Canvas.createCanvas(size[0], size[1], canvasClass),
                point = this._getCacheImageAnchor(size[0], size[1]);

            var context = canvas.getContext('2d');
            var gradient = isGradient(this.strokeAndFill['lineColor']) || isGradient(this.strokeAndFill['polygonFill']);

            if (!gradient) {
                this.prepareCanvas(context, this.strokeAndFill, resources);
            }

            this._drawVectorMarker(context, point, resources);

            return canvas;
        };

        _proto._stampSymbol = function _stampSymbol() {
            if (!this._stamp) {
                this._stamp = [this.style['markerType'], isGradient(this.style['markerFill']) ? getGradientStamp(this.style['markerFill']) : this.style['markerFill'], this.style['markerFillOpacity'], this.style['markerFillPatternFile'], isGradient(this.style['markerLineColor']) ? getGradientStamp(this.style['markerLineColor']) : this.style['markerLineColor'], this.style['markerLineWidth'], this.style['markerLineOpacity'], this.style['markerLineDasharray'] ? this.style['markerLineDasharray'].join(',') : '', this.style['markerLinePatternFile'], this.style['markerWidth'], this.style['markerHeight'], this.style['markerHorizontalAlignment'], this.style['markerVerticalAlignment']].join('_');
            }

            return this._stamp;
        };

        _proto._getAnchor = function _getAnchor(w, h) {
            var shadow = 2 * (this.symbol['shadowBlur'] || 0),
                margin = shadow + this.padding;
            var p = getAlignPoint(new Size(w, h), this.style['markerHorizontalAlignment'], this.style['markerVerticalAlignment']);

            if (p.x !== -w / 2) {
                p.x -= sign(p.x + w / 2) * margin;
            }

            if (p.y !== -h / 2) {
                p.y -= sign(p.y + h / 2) * margin;
            }

            return p;
        };

        _proto._getCacheImageAnchor = function _getCacheImageAnchor(w, h) {
            var shadow = 2 * (this.symbol['shadowBlur'] || 0),
                margin = shadow + this.padding;
            var markerType = this.style['markerType'];

            if (markerType === 'bar' || markerType === 'pie' || markerType === 'pin') {
                return new Point(w / 2, h - margin);
            } else if (markerType === 'rectangle') {
                return new Point(margin, margin);
            } else {
                return new Point(w / 2, h / 2);
            }
        };

        _proto._getGraidentExtent = function _getGraidentExtent(points) {
            var e = new PointExtent(),
                dxdy = this.getDxDy(),
                m = this.getFixedExtent();

            if (Array.isArray(points)) {
                for (var i = points.length - 1; i >= 0; i--) {
                    e._combine(points[i]);
                }
            } else {
                e._combine(points);
            }

            e['xmin'] += m['xmin'] - dxdy.x;
            e['ymin'] += m['ymin'] - dxdy.y;
            e['xmax'] += m['xmax'] - dxdy.x;
            e['ymax'] += m['ymax'] - dxdy.y;
            return e;
        };

        _proto._drawVectorMarker = function _drawVectorMarker(ctx, point, resources) {
            var style = this.style,
                strokeAndFill = this.strokeAndFill,
                markerType = style['markerType'].toLowerCase(),
                vectorArray = VectorMarkerSymbolizer._getVectorPoints(markerType, style['markerWidth'], style['markerHeight']),
                lineOpacity = strokeAndFill['lineOpacity'],
                fillOpacity = strokeAndFill['polygonOpacity'];

            var gradient = isGradient(strokeAndFill['lineColor']) || isGradient(strokeAndFill['polygonFill']);

            if (gradient) {
                var gradientExtent;

                if (isGradient(strokeAndFill['lineColor'])) {
                    gradientExtent = this._getGraidentExtent(point);
                    strokeAndFill['lineGradientExtent'] = gradientExtent.expand(strokeAndFill['lineWidth']);
                }

                if (isGradient(strokeAndFill['polygonFill'])) {
                    if (!gradientExtent) {
                        gradientExtent = this._getGraidentExtent(point);
                    }

                    strokeAndFill['polygonGradientExtent'] = gradientExtent;
                }

                this.prepareCanvas(ctx, strokeAndFill, resources);
            }

            var width = style['markerWidth'],
                height = style['markerHeight'],
                hLineWidth = style['markerLineWidth'] / 2;

            if (markerType === 'ellipse') {
                Canvas.ellipse(ctx, point, width / 2, height / 2, height / 2, lineOpacity, fillOpacity);
            } else if (markerType === 'cross' || markerType === 'x') {
                for (var j = vectorArray.length - 1; j >= 0; j--) {
                    vectorArray[j]._add(point);
                }

                Canvas.path(ctx, vectorArray.slice(0, 2), lineOpacity);
                Canvas.path(ctx, vectorArray.slice(2, 4), lineOpacity);
            } else if (markerType === 'diamond' || markerType === 'bar' || markerType === 'square' || markerType === 'rectangle' || markerType === 'triangle') {
                if (markerType === 'bar') {
                    point = point.add(0, -hLineWidth);
                } else if (markerType === 'rectangle') {
                    point = point.add(hLineWidth, hLineWidth);
                }

                for (var _j = vectorArray.length - 1; _j >= 0; _j--) {
                    vectorArray[_j]._add(point);
                }

                Canvas.polygon(ctx, vectorArray, lineOpacity, fillOpacity);
            } else if (markerType === 'pin') {
                point = point.add(0, -hLineWidth);

                for (var _j2 = vectorArray.length - 1; _j2 >= 0; _j2--) {
                    vectorArray[_j2]._add(point);
                }

                var lineCap = ctx.lineCap;
                ctx.lineCap = 'round';
                Canvas.bezierCurveAndFill(ctx, vectorArray, lineOpacity, fillOpacity);
                ctx.lineCap = lineCap;
            } else if (markerType === 'pie') {
                point = point.add(0, hLineWidth);
                var angle = Math.atan(width / 2 / height) * 180 / Math.PI;
                var _lineCap = ctx.lineCap;
                ctx.lineCap = 'round';
                Canvas.sector(ctx, point, height, [90 - angle, 90 + angle], lineOpacity, fillOpacity);
                ctx.lineCap = _lineCap;
            } else {
                throw new Error('unsupported markerType: ' + markerType);
            }
        };

        _proto.getPlacement = function getPlacement() {
            return this.symbol['markerPlacement'];
        };

        _proto.getRotation = function getRotation() {
            var r = this.style['markerRotation'];

            if (!isNumber(r)) {
                return null;
            }

            return -r * Math.PI / 180;
        };

        _proto.getFixedExtent = function getFixedExtent() {
            var dxdy = this.getDxDy(),
                padding = this.padding * 2;

            var size = this._calMarkerSize().map(function(d) {
                return d - padding;
            });

            var alignPoint = this._getAnchor(size[0], size[1]);

            var result = new PointExtent(dxdy.add(0, 0), dxdy.add(size[0], size[1]));

            result._add(alignPoint);

            var rotation = this.getRotation();

            if (rotation) {
                result = this._rotateExtent(result, rotation);
            }

            return result;
        };

        _proto.translate = function translate() {
            var s = this.symbol;
            var result = {
                'markerType': getValueOrDefault(s['markerType'], 'ellipse'),
                'markerFill': getValueOrDefault(s['markerFill'], '#00f'),
                'markerFillOpacity': getValueOrDefault(s['markerFillOpacity'], 1),
                'markerFillPatternFile': getValueOrDefault(s['markerFillPatternFile'], null),
                'markerLineColor': getValueOrDefault(s['markerLineColor'], '#000'),
                'markerLineWidth': getValueOrDefault(s['markerLineWidth'], 1),
                'markerLineOpacity': getValueOrDefault(s['markerLineOpacity'], 1),
                'markerLineDasharray': getValueOrDefault(s['markerLineDasharray'], []),
                'markerLinePatternFile': getValueOrDefault(s['markerLinePatternFile'], null),
                'markerDx': getValueOrDefault(s['markerDx'], 0),
                'markerDy': getValueOrDefault(s['markerDy'], 0),
                'markerWidth': getValueOrDefault(s['markerWidth'], 10),
                'markerHeight': getValueOrDefault(s['markerHeight'], 10),
                'markerRotation': getValueOrDefault(s['markerRotation'], 0)
            };
            var markerType = result['markerType'];
            var ha, va;

            if (markerType === 'bar' || markerType === 'pie' || markerType === 'pin') {
                ha = 'middle';
                va = 'top';
            } else if (markerType === 'rectangle') {
                ha = 'right';
                va = 'bottom';
            } else {
                ha = 'middle';
                va = 'middle';
            }

            result['markerHorizontalAlignment'] = getValueOrDefault(s['markerHorizontalAlignment'], ha);
            result['markerVerticalAlignment'] = getValueOrDefault(s['markerVerticalAlignment'], va);

            if (isNumber(s['markerOpacity'])) {
                if (isNumber(s['markerFillOpacity'])) {
                    result['markerFillOpacity'] *= s['markerOpacity'];
                }

                if (isNumber(s['markerLineOpacity'])) {
                    result['markerLineOpacity'] *= s['markerOpacity'];
                }
            }

            return result;
        };

        VectorMarkerSymbolizer.translateLineAndFill = function translateLineAndFill(s) {
            var result = {
                'lineColor': s['markerLineColor'],
                'linePatternFile': s['markerLinePatternFile'],
                'lineWidth': s['markerLineWidth'],
                'lineOpacity': s['markerLineOpacity'],
                'lineDasharray': s['markerLineDasharray'],
                'lineCap': 'butt',
                'lineJoin': 'round',
                'polygonFill': s['markerFill'],
                'polygonPatternFile': s['markerFillPatternFile'],
                'polygonOpacity': s['markerFillOpacity']
            };

            if (result['lineWidth'] === 0) {
                result['lineOpacity'] = 0;
            }

            return result;
        };

        VectorMarkerSymbolizer._getVectorPoints = function _getVectorPoints(markerType, width, height) {
            var hh = height / 2,
                hw = width / 2;
            var left = 0,
                top = 0;
            var v0, v1, v2, v3;

            if (markerType === 'triangle') {
                v0 = new Point(left, top - hh);
                v1 = new Point(left - hw, top + hh);
                v2 = new Point(left + hw, top + hh);
                return [v0, v1, v2];
            } else if (markerType === 'cross') {
                v0 = new Point(left - hw, top);
                v1 = new Point(left + hw, top);
                v2 = new Point(left, top - hh);
                v3 = new Point(left, top + hh);
                return [v0, v1, v2, v3];
            } else if (markerType === 'diamond') {
                v0 = new Point(left - hw, top);
                v1 = new Point(left, top - hh);
                v2 = new Point(left + hw, top);
                v3 = new Point(left, top + hh);
                return [v0, v1, v2, v3];
            } else if (markerType === 'square') {
                v0 = new Point(left - hw, top + hh);
                v1 = new Point(left + hw, top + hh);
                v2 = new Point(left + hw, top - hh);
                v3 = new Point(left - hw, top - hh);
                return [v0, v1, v2, v3];
            } else if (markerType === 'rectangle') {
                v0 = new Point(left, top);
                v1 = v0.add(width, 0);
                v2 = v0.add(width, height);
                v3 = v0.add(0, height);
                return [v0, v1, v2, v3];
            } else if (markerType === 'x') {
                v0 = new Point(left - hw, top + hh);
                v1 = new Point(left + hw, top - hh);
                v2 = new Point(left + hw, top + hh);
                v3 = new Point(left - hw, top - hh);
                return [v0, v1, v2, v3];
            } else if (markerType === 'bar') {
                v0 = new Point(left - hw, top - height);
                v1 = new Point(left + hw, top - height);
                v2 = new Point(left + hw, top);
                v3 = new Point(left - hw, top);
                return [v0, v1, v2, v3];
            } else if (markerType === 'pin') {
                var extWidth = height * Math.atan(hw / hh);
                v0 = new Point(left, top);
                v1 = new Point(left - extWidth, top - height);
                v2 = new Point(left + extWidth, top - height);
                v3 = new Point(left, top);
                return [v0, v1, v2, v3];
            }

            return [];
        };

        return VectorMarkerSymbolizer;
    }(PointSymbolizer);

    var DebugSymbolizer = function(_PointSymbolizer) {
        _inheritsLoose(DebugSymbolizer, _PointSymbolizer);

        function DebugSymbolizer() {
            return _PointSymbolizer.apply(this, arguments) || this;
        }

        var _proto = DebugSymbolizer.prototype;

        _proto.getPlacement = function getPlacement() {
            return 'point';
        };

        _proto.getDxDy = function getDxDy() {
            return new Point(0, 0);
        };

        _proto.symbolize = function symbolize(ctx) {
            var geometry = this.geometry,
                layer = geometry.getLayer();

            if (!geometry.options['debug'] && layer && !layer.options['debug']) {
                return;
            }

            var map = this.getMap();

            if (!map || map.isZooming()) {
                return;
            }

            var color = layer.options['debugOutline'],
                op = 1;
            ctx.strokeStyle = color;
            ctx.fillStyle = color;
            var outline = this.getPainter().getContainerExtent().toArray();
            Canvas.polygon(ctx, [outline], op, 0);

            var points = this._getRenderContainerPoints(),
                id = this.geometry.getId(),
                cross = VectorMarkerSymbolizer._getVectorPoints('cross', 10, 10);

            for (var i = 0; i < points.length; i++) {
                var p = points[i];

                if (!isNil(id)) {
                    Canvas.fillText(ctx, id, p.add(8, -4), color);
                }

                var c = [];

                for (var ii = 0; ii < cross.length; ii++) {
                    c.push(cross[ii].add(p));
                }

                Canvas.path(ctx, c.slice(0, 2), op);
                Canvas.path(ctx, c.slice(2, 4), op);
            }
        };

        return DebugSymbolizer;
    }(PointSymbolizer);

    var ImageMarkerSymbolizer = function(_PointSymbolizer) {
        _inheritsLoose(ImageMarkerSymbolizer, _PointSymbolizer);

        ImageMarkerSymbolizer.test = function test(symbol) {
            if (!symbol) {
                return false;
            }

            if (!isNil(symbol['markerFile'])) {
                return true;
            }

            return false;
        };

        function ImageMarkerSymbolizer(symbol, geometry, painter) {
            var _this;

            _this = _PointSymbolizer.call(this, symbol, geometry, painter) || this;
            _this.style = _this._defineStyle(_this.translate());
            return _this;
        }

        var _proto = ImageMarkerSymbolizer.prototype;

        _proto.symbolize = function symbolize(ctx, resources) {
            var style = this.style;

            if (!this.painter.isHitTesting() && (style['markerWidth'] === 0 || style['markerHeight'] === 0 || style['markerOpacity'] === 0)) {
                return;
            }

            var cookedPoints = this._getRenderContainerPoints();

            if (!isArrayHasData(cookedPoints)) {
                return;
            }

            var img = this._getImage(resources);

            if (!img) {
                if (typeof console !== 'undefined') {
                    console.warn('no img found for ' + (this.style['markerFile'] || this._url[0]));
                }

                return;
            }

            this._prepareContext(ctx);

            var width = style['markerWidth'];
            var height = style['markerHeight'];

            if (!isNumber(width) || !isNumber(height)) {
                width = img.width;
                height = img.height;
                style['markerWidth'] = width;
                style['markerHeight'] = height;
                var imgURL = [style['markerFile'], style['markerWidth'], style['markerHeight']];

                if (!resources.isResourceLoaded(imgURL)) {
                    resources.addResource(imgURL, img);
                }

                var painter = this.getPainter();

                if (!painter.isSpriting()) {
                    painter.removeCache();
                }
            }

            var alpha;

            if (this.symbol['markerType'] !== 'path' && isNumber(style['markerOpacity']) && style['markerOpacity'] < 1) {
                alpha = ctx.globalAlpha;
                ctx.globalAlpha *= style['markerOpacity'];
            }

            var alignPoint = getAlignPoint(new Size(width, height), style['markerHorizontalAlignment'], style['markerVerticalAlignment']);

            for (var i = 0, len = cookedPoints.length; i < len; i++) {
                var p = cookedPoints[i];

                var origin = this._rotate(ctx, p, this._getRotationAt(i));

                if (origin) {
                    p = origin;
                }

                Canvas.image(ctx, img, p.x + alignPoint.x, p.y + alignPoint.y, width, height);

                if (origin) {
                    ctx.restore();
                }
            }

            if (alpha !== undefined) {
                ctx.globalAlpha = alpha;
            }
        };

        _proto._getImage = function _getImage(resources) {
            var img = !resources ? null : resources.getImage([this.style['markerFile'], this.style['markerWidth'], this.style['markerHeight']]);
            return img;
        };

        _proto.getPlacement = function getPlacement() {
            return this.symbol['markerPlacement'];
        };

        _proto.getRotation = function getRotation() {
            var r = this.style['markerRotation'];

            if (!isNumber(r)) {
                return null;
            }

            return -r * Math.PI / 180;
        };

        _proto.getDxDy = function getDxDy() {
            var s = this.style;
            var dx = s['markerDx'],
                dy = s['markerDy'];
            return new Point(dx, dy);
        };

        _proto.getFixedExtent = function getFixedExtent(resources) {
            var style = this.style;
            var url = style['markerFile'],
                img = resources ? resources.getImage(url) : null;
            var width = style['markerWidth'] || (img ? img.width : 0),
                height = style['markerHeight'] || (img ? img.height : 0);
            var dxdy = this.getDxDy();
            var alignPoint = getAlignPoint(new Size(width, height), style['markerHorizontalAlignment'], style['markerVerticalAlignment']);
            var result = new PointExtent(dxdy.add(0, 0), dxdy.add(width, height));

            result._add(alignPoint);

            var rotation = this.getRotation();

            if (rotation) {
                result = this._rotateExtent(result, rotation);
            }

            return result;
        };

        _proto.translate = function translate() {
            var s = this.symbol;
            return {
                'markerFile': s['markerFile'],
                'markerOpacity': getValueOrDefault(s['markerOpacity'], 1),
                'markerWidth': getValueOrDefault(s['markerWidth'], null),
                'markerHeight': getValueOrDefault(s['markerHeight'], null),
                'markerRotation': getValueOrDefault(s['markerRotation'], 0),
                'markerDx': getValueOrDefault(s['markerDx'], 0),
                'markerDy': getValueOrDefault(s['markerDy'], 0),
                'markerHorizontalAlignment': getValueOrDefault(s['markerHorizontalAlignment'], 'middle'),
                'markerVerticalAlignment': getValueOrDefault(s['markerVerticalAlignment'], 'top')
            };
        };

        return ImageMarkerSymbolizer;
    }(PointSymbolizer);

    var TEMP_COORD0$1 = new Coordinate(0, 0);
    var TEMP_COORD1$1 = new Coordinate(0, 0);

    var StrokeAndFillSymbolizer = function(_CanvasSymbolizer) {
        _inheritsLoose(StrokeAndFillSymbolizer, _CanvasSymbolizer);

        StrokeAndFillSymbolizer.test = function test(symbol, geometry) {
            if (!symbol) {
                return false;
            }

            if (geometry && geometry.type === 'Point') {
                return false;
            }

            for (var p in symbol) {
                var f = p.slice(0, 4);

                if (f === 'line' || f === 'poly') {
                    return true;
                }
            }

            return false;
        };

        function StrokeAndFillSymbolizer(symbol, geometry, painter) {
            var _this;

            _this = _CanvasSymbolizer.call(this) || this;
            _this.symbol = symbol;
            _this.geometry = geometry;
            _this.painter = painter;

            if (geometry.type === 'Point') {
                return _assertThisInitialized(_this);
            }

            _this.style = _this._defineStyle(_this.translate());
            return _this;
        }

        var _proto = StrokeAndFillSymbolizer.prototype;

        _proto.symbolize = function symbolize(ctx, resources) {
            var style = this.style;

            if (style['polygonOpacity'] === 0 && style['lineOpacity'] === 0 && !this.painter.isHitTesting()) {
                return;
            }

            var paintParams = this._getPaintParams();

            if (!paintParams) {
                return;
            }

            this._prepareContext(ctx);

            var isGradient$$1 = isGradient(style['lineColor']),
                isPath = this.geometry.getJSONType() === 'Polygon' || this.geometry.type === 'LineString';

            if (isGradient$$1 && (style['lineColor']['places'] || !isPath)) {
                style['lineGradientExtent'] = this.getPainter().getContainerExtent()._expand(style['lineWidth']);
            }

            if (isGradient(style['polygonFill'])) {
                style['polygonGradientExtent'] = this.getPainter().getContainerExtent();
            }

            var points = paintParams[0],
                isSplitted = this.geometry.getJSONType() === 'Polygon' && points.length > 0 && Array.isArray(points[0][0]) || this.geometry.type === 'LineString' && points.length > 0 && Array.isArray(points[0]);

            if (isSplitted) {
                for (var i = 0; i < points.length; i++) {
                    this.prepareCanvas(ctx, style, resources);

                    if (isGradient$$1 && isPath && !style['lineColor']['places']) {
                        this._createGradient(ctx, points[i], style['lineColor']);
                    }

                    var params = [ctx, points[i]];

                    if (paintParams.length > 1) {
                        params.push.apply(params, paintParams.slice(1));
                    }

                    params.push(style['lineOpacity'], style['polygonOpacity'], style['lineDasharray']);

                    this.geometry._paintOn.apply(this.geometry, params);
                }
            } else {
                this.prepareCanvas(ctx, style, resources);

                if (isGradient$$1 && isPath && !style['lineColor']['places']) {
                    this._createGradient(ctx, points, style['lineColor']);
                }

                var _params = [ctx];

                _params.push.apply(_params, paintParams);

                _params.push(style['lineOpacity'], style['polygonOpacity'], style['lineDasharray']);

                this.geometry._paintOn.apply(this.geometry, _params);
            }

            if (ctx.setLineDash && Array.isArray(style['lineDasharray'])) {
                ctx.setLineDash([]);
            }
        };

        _proto.get2DExtent = function get2DExtent() {
            var map = this.getMap();

            var extent = this.geometry._getPrjExtent();

            if (!extent) {
                return null;
            }

            if (!this._extMin || !this._extMax) {
                this._extMin = new Coordinate(0, 0);
                this._extMax = new Coordinate(0, 0);
            }

            this._extMin.x = extent['xmin'];
            this._extMin.y = extent['ymin'];
            this._extMax.x = extent['xmax'];
            this._extMax.y = extent['ymax'];

            var min = map._prjToPoint(this._extMin, undefined, TEMP_COORD0$1),
                max = map._prjToPoint(this._extMax, undefined, TEMP_COORD1$1);

            if (!this._pxExtent) {
                this._pxExtent = new PointExtent(min, max);
            } else {
                this._pxExtent.set(Math.min(min.x, max.x), Math.min(min.y, max.y), Math.max(min.x, max.x), Math.max(min.y, max.y));
            }

            return this._pxExtent;
        };

        _proto.getFixedExtent = function getFixedExtent() {
            var t = this.style['lineWidth'] / 2;
            return new PointExtent(-t, -t, t, t);
        };

        _proto._getPaintParams = function _getPaintParams() {
            return this.getPainter().getPaintParams(this.style['lineDx'], this.style['lineDy']);
        };

        _proto.translate = function translate() {
            var s = this.symbol;
            var result = {
                'lineColor': getValueOrDefault(s['lineColor'], '#000'),
                'lineWidth': getValueOrDefault(s['lineWidth'], 2),
                'lineOpacity': getValueOrDefault(s['lineOpacity'], 1),
                'lineDasharray': getValueOrDefault(s['lineDasharray'], []),
                'lineCap': getValueOrDefault(s['lineCap'], 'butt'),
                'lineJoin': getValueOrDefault(s['lineJoin'], 'miter'),
                'linePatternFile': getValueOrDefault(s['linePatternFile'], null),
                'lineDx': getValueOrDefault(s['lineDx'], 0),
                'lineDy': getValueOrDefault(s['lineDy'], 0),
                'polygonFill': getValueOrDefault(s['polygonFill'], null),
                'polygonOpacity': getValueOrDefault(s['polygonOpacity'], 1),
                'polygonPatternFile': getValueOrDefault(s['polygonPatternFile'], null),
                'polygonPatternDx': getValueOrDefault(s['polygonPatternDx'], 0),
                'polygonPatternDy': getValueOrDefault(s['polygonPatternDy'], 0),
                'linePatternDx': getValueOrDefault(s['linePatternDx'], 0),
                'linePatternDy': getValueOrDefault(s['linePatternDy'], 0)
            };

            if (result['lineWidth'] === 0) {
                result['lineOpacity'] = 0;
            }

            if (this.geometry.type === 'LineString' && !result['polygonFill']) {
                result['polygonFill'] = result['lineColor'];
            }

            return result;
        };

        _proto._createGradient = function _createGradient(ctx, points, lineColor) {
            if (!Array.isArray(points) || !points.length) {
                return;
            }

            var len = points.length;
            var grad = ctx.createLinearGradient(points[0].x, points[0].y, points[len - 1].x, points[len - 1].y);
            lineColor['colorStops'].forEach(function(stop) {
                grad.addColorStop.apply(grad, stop);
            });
            ctx.strokeStyle = grad;
        };

        return StrokeAndFillSymbolizer;
    }(CanvasSymbolizer);

    var CACHE_KEY = '___text_symbol_cache';

    var TextMarkerSymbolizer = function(_PointSymbolizer) {
        _inheritsLoose(TextMarkerSymbolizer, _PointSymbolizer);

        TextMarkerSymbolizer.test = function test(symbol) {
            if (!symbol) {
                return false;
            }

            if (!isNil(symbol['textName'])) {
                return true;
            }

            return false;
        };

        function TextMarkerSymbolizer(symbol, geometry, painter) {
            var _this;

            _this = _PointSymbolizer.call(this, symbol, geometry, painter) || this;
            _this._dynamic = hasFunctionDefinition(symbol);
            _this.style = _this._defineStyle(_this.translate());

            if (_this.style['textWrapWidth'] === 0) {
                return _assertThisInitialized(_this);
            }

            _this.strokeAndFill = _this._defineStyle(_this.translateLineAndFill(_this.style));
            var textContent = replaceVariable(_this.style['textName'], _this.geometry.getProperties());

            if (!_this._dynamic) {
                _this._cacheKey = genCacheKey(textContent, _this.style);
            }

            _this._descText(textContent);

            return _this;
        }

        var _proto = TextMarkerSymbolizer.prototype;

        _proto.symbolize = function symbolize(ctx, resources) {
            if (!this.painter.isHitTesting() && (this.style['textSize'] === 0 || !this.style['textOpacity'] && (!this.style['textHaloRadius'] || !this.style['textHaloOpacity']) || this.style['textWrapWidth'] === 0)) {
                return;
            }

            var cookedPoints = this._getRenderContainerPoints();

            if (!isArrayHasData(cookedPoints)) {
                return;
            }

            var style = this.style,
                strokeAndFill = this.strokeAndFill;
            var textContent = replaceVariable(this.style['textName'], this.geometry.getProperties());

            this._descText(textContent);

            this._prepareContext(ctx);

            this.prepareCanvas(ctx, strokeAndFill, resources);
            Canvas.prepareCanvasFont(ctx, style);

            for (var i = 0, len = cookedPoints.length; i < len; i++) {
                var p = cookedPoints[i];

                var origin = this._rotate(ctx, p, this._getRotationAt(i));

                if (origin) {
                    p = origin;
                }

                Canvas.text(ctx, textContent, p, style, this.textDesc);

                if (origin) {
                    ctx.restore();
                }
            }
        };

        _proto.getPlacement = function getPlacement() {
            return this.symbol['textPlacement'];
        };

        _proto.getRotation = function getRotation() {
            var r = this.style['textRotation'];

            if (!isNumber(r)) {
                return null;
            }

            return -r * Math.PI / 180;
        };

        _proto.getDxDy = function getDxDy() {
            var s = this.style;
            return new Point(s['textDx'], s['textDy']);
        };

        _proto.getFixedExtent = function getFixedExtent() {
            var dxdy = this.getDxDy(),
                style = this.style;
            var size = this.textDesc['size'];
            var alignPoint = getAlignPoint(size, style['textHorizontalAlignment'], style['textVerticalAlignment']);
            var alignW = alignPoint.x,
                alignH = alignPoint.y;

            if (style['textHaloRadius']) {
                var r = style['textHaloRadius'];
                size = size.add(r * 2, r * 2);
            }

            var result = new PointExtent(dxdy.add(alignW, alignH), dxdy.add(alignW + size['width'], alignH + size['height']));
            var rotation = this.getRotation();

            if (rotation) {
                result = this._rotateExtent(result, rotation);
            }

            return result;
        };

        _proto.translate = function translate() {
            var s = this.symbol;
            var result = {
                'textName': s['textName'],
                'textFaceName': getValueOrDefault(s['textFaceName'], 'monospace'),
                'textWeight': getValueOrDefault(s['textWeight'], 'normal'),
                'textStyle': getValueOrDefault(s['textStyle'], 'normal'),
                'textSize': getValueOrDefault(s['textSize'], DEFAULT_TEXT_SIZE),
                'textFont': getValueOrDefault(s['textFont'], null),
                'textFill': getValueOrDefault(s['textFill'], '#000'),
                'textOpacity': getValueOrDefault(s['textOpacity'], 1),
                'textHaloFill': getValueOrDefault(s['textHaloFill'], '#ffffff'),
                'textHaloRadius': getValueOrDefault(s['textHaloRadius'], 0),
                'textHaloOpacity': getValueOrDefault(s['textHaloOpacity'], 1),
                'textWrapWidth': getValueOrDefault(s['textWrapWidth'], null),
                'textWrapCharacter': getValueOrDefault(s['textWrapCharacter'], '\n'),
                'textLineSpacing': getValueOrDefault(s['textLineSpacing'], 0),
                'textDx': getValueOrDefault(s['textDx'], 0),
                'textDy': getValueOrDefault(s['textDy'], 0),
                'textHorizontalAlignment': getValueOrDefault(s['textHorizontalAlignment'], 'middle'),
                'textVerticalAlignment': getValueOrDefault(s['textVerticalAlignment'], 'middle'),
                'textAlign': getValueOrDefault(s['textAlign'], 'center'),
                'textRotation': getValueOrDefault(s['textRotation'], 0),
                'textMaxWidth': getValueOrDefault(s['textMaxWidth'], 0),
                'textMaxHeight': getValueOrDefault(s['textMaxHeight'], 0)
            };

            if (result['textMaxWidth'] > 0 && (!result['textWrapWidth'] || result['textWrapWidth'] > result['textMaxWidth'])) {
                if (!result['textWrapWidth']) {
                    result['textMaxHeight'] = 1;
                }

                result['textWrapWidth'] = result['textMaxWidth'];
            }

            return result;
        };

        _proto.translateLineAndFill = function translateLineAndFill(s) {
            return {
                'lineColor': s['textHaloRadius'] ? s['textHaloFill'] : s['textFill'],
                'lineWidth': s['textHaloRadius'],
                'lineOpacity': s['textOpacity'],
                'lineDasharray': null,
                'lineCap': 'butt',
                'lineJoin': 'round',
                'polygonFill': s['textFill'],
                'polygonOpacity': s['textOpacity']
            };
        };

        _proto._descText = function _descText(textContent) {
            if (this._dynamic) {
                this.textDesc = this._measureText(textContent);
                return;
            }

            this.textDesc = this._loadFromCache();

            if (!this.textDesc) {
                this.textDesc = this._measureText(textContent);

                this._storeToCache(this.textDesc);
            }
        };

        _proto._measureText = function _measureText(textContent) {
            var maxHeight = this.style['textMaxHeight'];
            var textDesc = splitTextToRow(textContent, this.style);

            if (maxHeight && maxHeight < textDesc.size.height) {
                textDesc.size.height = maxHeight;
            }

            return textDesc;
        };

        _proto._storeToCache = function _storeToCache(textDesc) {
            if (IS_NODE) {
                return;
            }

            if (!this.geometry[CACHE_KEY]) {
                this.geometry[CACHE_KEY] = {};
            }

            this.geometry[CACHE_KEY][this._cacheKey] = {
                'desc': textDesc,
                'active': true
            };
        };

        _proto._loadFromCache = function _loadFromCache() {
            if (!this.geometry[CACHE_KEY]) {
                return null;
            }

            var cache = this.geometry[CACHE_KEY][this._cacheKey];

            if (!cache) {
                return null;
            }

            cache.active = true;
            return cache.desc;
        };

        return TextMarkerSymbolizer;
    }(PointSymbolizer);
    TextMarkerSymbolizer.CACHE_KEY = CACHE_KEY;

    function genCacheKey(textContent, style) {
        var key = [textContent];

        for (var p in style) {
            if (style.hasOwnProperty(p) && p.length > 4 && p.substring(0, 4) === 'text') {
                key.push(p + '=' + style[p]);
            }
        }

        return key.join('-');
    }

    var VectorPathMarkerSymbolizer = function(_ImageMarkerSymbolize) {
        _inheritsLoose(VectorPathMarkerSymbolizer, _ImageMarkerSymbolize);

        VectorPathMarkerSymbolizer.test = function test(symbol) {
            if (!symbol) {
                return false;
            }

            if (isNil(symbol['markerFile']) && symbol['markerType'] === 'path') {
                return true;
            }

            return false;
        };

        function VectorPathMarkerSymbolizer(symbol, geometry, painter) {
            var _this;

            if (isNil(symbol['markerWidth'])) {
                symbol['markerWidth'] = 80;
            }

            if (isNil(symbol['markerHeight'])) {
                symbol['markerHeight'] = 80;
            }

            _this = _ImageMarkerSymbolize.call(this, symbol, geometry, painter) || this;
            symbol = extend(symbol, _this.translate());

            var style = _this.style = _this._defineStyle(symbol);

            if (Browser$1.gecko) {
                _this._url = [getMarkerPathBase64(style, style['markerWidth'], style['markerHeight']), style['markerWidth'], style['markerHeight']];
            } else {
                _this._url = [getMarkerPathBase64(style), style['markerWidth'], style['markerHeight']];
            }

            return _this;
        }

        var _proto = VectorPathMarkerSymbolizer.prototype;

        _proto._prepareContext = function _prepareContext() {};

        _proto._getImage = function _getImage(resources) {
            var _this2 = this;

            if (resources && resources.isResourceLoaded(this._url)) {
                return resources.getImage(this._url);
            }

            var painter = this.painter;
            var image = new Image();

            image.onload = function() {
                var renderer = painter.getLayer() && painter.getLayer().getRenderer();

                if (renderer) {
                    renderer.setToRedraw();
                }
            };

            image.onerror = function(err) {
                if (err && typeof console !== 'undefined') {
                    console.warn(err);
                }

                resources.markErrorResource(_this2._url);
            };

            image.src = this._url[0];

            if (resources) {
                resources.addResource(this._url, image);
            }

            return image;
        };

        return VectorPathMarkerSymbolizer;
    }(ImageMarkerSymbolizer);

    var defaultSymbol = {
        lineWidth: 1,
        polygonFill: '#fff',
        polygonOpacity: 0.5
    };

    var DrawAltitudeSymbolizer = function(_PointSymbolizer) {
        _inheritsLoose(DrawAltitudeSymbolizer, _PointSymbolizer);

        DrawAltitudeSymbolizer.test = function test(symbol, geometry) {
            var layer = geometry.getLayer();

            if (!layer) {
                return false;
            }

            var type = geometry.getJSONType();
            return type === 'Marker' || type === 'LineString';
        };

        function DrawAltitudeSymbolizer(symbol, geometry, painter) {
            var _this;

            _this = _PointSymbolizer.call(this, symbol, geometry, painter) || this;
            _this.style = geometry.getLayer().options['drawAltitude'];

            if (!_this.style || !isObject(_this.style)) {
                _this.style = {
                    'lineWidth': 2
                };
            }

            if (!_this.style['lineWidth']) {
                _this.style['lineWidth'] = 0;
            }

            _this.dxdy = _this._defineStyle({
                'dx': symbol['textDx'] || symbol['markerDx'],
                'dy': symbol['textDy'] || symbol['markerDy']
            });
            return _this;
        }

        var _proto = DrawAltitudeSymbolizer.prototype;

        _proto.symbolize = function symbolize(ctx) {
            var layer = this.geometry.getLayer();

            if (!layer.options['drawAltitude']) {
                return;
            }

            var properties = this.geometry.getProperties();

            if (!properties || !properties[layer.options['altitudeProperty']]) {
                return;
            }

            var style = this._getStyle();

            this._prepareContext(ctx);

            if (this.geometry.type === 'LineString') {
                var paintParams = this._getPaintParams(style['lineDx'], style['lineDy']);

                if (!paintParams) {
                    return;
                }

                var groundPoints = this.getPainter().getPaintParams(style['lineDx'], style['lineDy'], true)[0];

                this._drawLineAltitude(ctx, paintParams[0], groundPoints);
            } else {
                var point = this._getRenderContainerPoints(),
                    groundPoint = this._getRenderContainerPoints(true);

                if (!point || point.length === 0) {
                    return;
                }

                this._drawMarkerAltitude(ctx, point[0], groundPoint[0]);
            }
        };

        _proto.getDxDy = function getDxDy() {
            var s = this.dxdy;
            return new Point(s['dx'] || 0, s['dy'] || 0);
        };

        _proto.get2DExtent = function get2DExtent() {
            if (this.geometry.type === 'LineString') {
                return StrokeAndFillSymbolizer.prototype.get2DExtent.apply(this);
            } else {
                return _PointSymbolizer.prototype.get2DExtent.call(this);
            }
        };

        _proto.getPlacement = function getPlacement() {
            return 'point';
        };

        _proto._getPaintParams = function _getPaintParams(dx, dy) {
            return this.getPainter().getPaintParams(dx || 0, dy || 0);
        };

        _proto._drawMarkerAltitude = function _drawMarkerAltitude(ctx, point, groundPoint) {
            var style = this._getStyle();

            this.prepareCanvas(ctx, style);
            Canvas.path(ctx, [point, groundPoint], style['lineOpacity'], null, style['lineDasharray']);
        };

        _proto._drawLineAltitude = function _drawLineAltitude(ctx, points, groundPoints) {
            var style = this._getStyle();

            var isSplitted = points.length > 0 && Array.isArray(points[0]);

            if (isSplitted) {
                for (var i = 0; i < points.length; i++) {
                    this._drawLine(ctx, points[i], groundPoints[i]);
                }
            } else {
                this._drawLine(ctx, points, groundPoints);
            }

            if (ctx.setLineDash && Array.isArray(style['lineDasharray'])) {
                ctx.setLineDash([]);
            }
        };

        _proto._drawLine = function _drawLine(ctx, points, groundPoints) {
            var style = this._getStyle();

            this.prepareCanvas(ctx, style);

            for (var i = 0, l = points.length - 1; i < l; i++) {
                Canvas.polygon(ctx, [points[i], points[i + 1], groundPoints[i + 1], groundPoints[i]], style['lineOpacity'], style['polygonOpacity'], style['lineDasharray']);
            }
        };

        _proto._getStyle = function _getStyle() {
            var style = this.geometry.getLayer().options['drawAltitude'];

            if (!isObject(style)) {
                style = defaultSymbol;
            }

            if (!style['lineWidth']) {
                style['lineWidth'] = 0;
                style['lineOpacity'] = 0;
            }

            return style;
        };

        return DrawAltitudeSymbolizer;
    }(PointSymbolizer);



    var index$3 = /*#__PURE__*/ Object.freeze({
        Symbolizer: Symbolizer,
        CanvasSymbolizer: CanvasSymbolizer,
        DebugSymbolizer: DebugSymbolizer,
        ImageMarkerSymbolizer: ImageMarkerSymbolizer,
        PointSymbolizer: PointSymbolizer,
        StrokeAndFillSymbolizer: StrokeAndFillSymbolizer,
        TextMarkerSymbolizer: TextMarkerSymbolizer,
        VectorMarkerSymbolizer: VectorMarkerSymbolizer,
        VectorPathMarkerSymbolizer: VectorPathMarkerSymbolizer,
        DrawAltitudeSymbolizer: DrawAltitudeSymbolizer
    });

    var registerSymbolizers = [DrawAltitudeSymbolizer, StrokeAndFillSymbolizer, ImageMarkerSymbolizer, VectorPathMarkerSymbolizer, VectorMarkerSymbolizer, TextMarkerSymbolizer];
    var testCanvas;
    var TEMP_POINT0$2 = new Point(0, 0);
    var TEMP_PAINT_EXTENT = new PointExtent();
    var TEMP_EXTENT$1 = new PointExtent();
    var TEMP_FIXED_EXTENT = new PointExtent();
    var TEMP_CLIP_EXTENT0 = new PointExtent();
    var TEMP_CLIP_EXTENT1 = new PointExtent();

    var Painter = function(_Class) {
        _inheritsLoose(Painter, _Class);

        function Painter(geometry) {
            var _this;

            _this = _Class.call(this) || this;
            _this.geometry = geometry;
            _this.symbolizers = _this._createSymbolizers();
            _this._altAtGLZoom = _this._getGeometryAltitude();
            return _this;
        }

        var _proto = Painter.prototype;

        _proto.getMap = function getMap() {
            return this.geometry.getMap();
        };

        _proto.getLayer = function getLayer() {
            return this.geometry.getLayer();
        };

        _proto._createSymbolizers = function _createSymbolizers() {
            var geoSymbol = this.getSymbol(),
                symbolizers = [],
                regSymbolizers = registerSymbolizers;
            var symbols = geoSymbol;

            if (!Array.isArray(geoSymbol)) {
                symbols = [geoSymbol];
            }

            for (var ii = symbols.length - 1; ii >= 0; ii--) {
                var symbol = symbols[ii];

                for (var i = regSymbolizers.length - 1; i >= 0; i--) {
                    if (regSymbolizers[i].test(symbol, this.geometry)) {
                        var symbolizer = new regSymbolizers[i](symbol, this.geometry, this);
                        symbolizers.push(symbolizer);

                        if (symbolizer instanceof PointSymbolizer) {
                            this._hasPoint = true;
                        }
                    }
                }
            }

            if (!symbolizers.length) {
                if (console) {
                    var id = this.geometry.getId();
                    console.warn('invalid symbol for geometry(' + (this.geometry ? this.geometry.getType() + (id ? ':' + id : '') : '') + ') to draw : ' + JSON.stringify(geoSymbol));
                }
            }

            this._debugSymbolizer = new DebugSymbolizer(geoSymbol, this.geometry, this);
            return symbolizers;
        };

        _proto.hasPoint = function hasPoint() {
            return !!this._hasPoint;
        };

        _proto.getRenderPoints = function getRenderPoints(placement) {
            if (!this._renderPoints) {
                this._renderPoints = {};
            }

            if (!placement) {
                placement = 'center';
            }

            if (!this._renderPoints[placement]) {
                this._renderPoints[placement] = this.geometry._getRenderPoints(placement);
            }

            return this._renderPoints[placement];
        };

        _proto.getPaintParams = function getPaintParams(dx, dy, ignoreAltitude) {
            var map = this.getMap(),
                geometry = this.geometry,
                res = map.getResolution(),
                pitched = map.getPitch() !== 0,
                rotated = map.getBearing() !== 0;
            var params = this._cachedParams;

            var paintAsPath = geometry._paintAsPath && geometry._paintAsPath();

            if (paintAsPath && this._unsimpledParams && res <= this._unsimpledParams._res) {
                params = this._unsimpledParams;
            } else if (!params || params._res !== map.getResolution() || this._pitched !== pitched && geometry._redrawWhenPitch() || this._rotated !== rotated && geometry._redrawWhenRotate()) {
                params = geometry._getPaintParams();

                if (!params) {
                    return null;
                }

                params._res = res;

                if (!geometry._simplified && paintAsPath) {
                    if (!this._unsimpledParams) {
                        this._unsimpledParams = params;
                    }

                    if (res > this._unsimpledParams._res) {
                        this._unsimpledParams._res = res;
                    }
                }

                this._cachedParams = params;
            }

            if (!params) {
                return null;
            }

            this._pitched = pitched;
            this._rotated = rotated;
            var zoomScale = map.getGLScale(),
                tr = [],
                points = params[0];
            var mapExtent = map.getContainerExtent();

            var cPoints = this._pointContainerPoints(points, dx, dy, ignoreAltitude, this._hitPoint && !mapExtent.contains(this._hitPoint));

            if (!cPoints) {
                return null;
            }

            tr.push(cPoints);

            for (var i = 1, l = params.length; i < l; i++) {
                if (isNumber(params[i]) || params[i] instanceof Size) {
                    if (isNumber(params[i])) {
                        tr.push(params[i] / zoomScale);
                    } else {
                        tr.push(params[i].multi(1 / zoomScale));
                    }
                } else {
                    tr.push(params[i]);
                }
            }

            return tr;
        };

        _proto._pointContainerPoints = function _pointContainerPoints(points, dx, dy, ignoreAltitude, disableClip, pointPlacement) {
            if (this._aboveCamera()) {
                return null;
            }

            var map = this.getMap(),
                glZoom = map.getGLZoom(),
                containerOffset = this.containerOffset;
            var cPoints;

            function pointContainerPoint(point, alt) {
                var p = map._pointToContainerPoint(point, glZoom, alt)._sub(containerOffset);

                if (dx || dy) {
                    p._add(dx || 0, dy || 0);
                }

                return p;
            }

            var altitude = this.getAltitude();

            if (Array.isArray(points)) {
                var geometry = this.geometry;
                var clipped;

                if (!disableClip && geometry.options['enableClip']) {
                    clipped = this._clip(points, altitude);
                } else {
                    clipped = {
                        points: points,
                        altitude: altitude
                    };
                }

                var clipPoints = clipped.points;
                altitude = clipped.altitude;

                if (ignoreAltitude) {
                    altitude = 0;
                }

                var alt = altitude;
                cPoints = [];

                for (var i = 0, l = clipPoints.length; i < l; i++) {
                    var c = clipPoints[i];

                    if (Array.isArray(c)) {
                        var cring = [];

                        for (var ii = 0, ll = c.length; ii < ll; ii++) {
                            var cc = c[ii];

                            if (Array.isArray(altitude)) {
                                if (altitude[i]) {
                                    alt = altitude[i][ii];
                                } else {
                                    alt = 0;
                                }
                            }

                            cring.push(pointContainerPoint(cc, alt));
                        }

                        cPoints.push(cring);
                    } else {
                        if (Array.isArray(altitude)) {
                            if (pointPlacement === 'vertex-last') {
                                alt = altitude[altitude.length - 1 - i];
                            } else if (pointPlacement === 'line') {
                                alt = (altitude[i] + altitude[i + 1]) / 2;
                            } else {
                                alt = altitude[i];
                            }
                        }

                        cPoints.push(pointContainerPoint(c, alt));
                    }
                }
            } else if (points instanceof Point) {
                if (ignoreAltitude) {
                    altitude = 0;
                }

                cPoints = map._pointToContainerPoint(points, glZoom, altitude)._sub(containerOffset);

                if (dx || dy) {
                    cPoints._add(dx, dy);
                }
            }

            return cPoints;
        };

        _proto._clip = function _clip(points, altitude) {
            var map = this.getMap(),
                geometry = this.geometry;
            var lineWidth = this.getSymbol()['lineWidth'];

            if (!isNumber(lineWidth)) {
                lineWidth = 4;
            }

            var extent2D = map._get2DExtent(undefined, TEMP_CLIP_EXTENT0)._expand(lineWidth);

            if (map.getPitch() > 0 && altitude) {
                var c = map.cameraLookAt;
                var pos = map.cameraPosition;
                TEMP_POINT0$2.set(pos.x, pos.y);
                extent2D = extent2D._combine(TEMP_POINT0$2._add(sign(c[0] - pos[0]), sign(c[1] - pos[1])));
            }

            var e = this.get2DExtent(null, TEMP_CLIP_EXTENT1);
            var clipPoints = points;

            if (e.within(extent2D)) {
                return {
                    points: clipPoints,
                    altitude: altitude
                };
            }

            var glExtent2D = map._get2DExtent(map.getGLZoom(), TEMP_CLIP_EXTENT0)._expand(lineWidth * map._glScale);

            var smoothness = geometry.options['smoothness'];

            if (geometry.getShell && this.geometry.getHoles && !smoothness) {
                if (!Array.isArray(points[0])) {
                    clipPoints = clipPolygon(points, glExtent2D);
                } else {
                    clipPoints = [];

                    for (var i = 0; i < points.length; i++) {
                        var part = clipPolygon(points[i], glExtent2D);

                        if (part.length) {
                            clipPoints.push(part);
                        }
                    }
                }
            } else if (geometry.getJSONType() === 'LineString' && !smoothness) {
                if (!Array.isArray(points[0])) {
                    clipPoints = clipLine(points, glExtent2D, false, !!smoothness);
                } else {
                    clipPoints = [];

                    for (var _i = 0; _i < points.length; _i++) {
                        pushIn(clipPoints, clipLine(points[_i], glExtent2D, false, !!smoothness));
                    }
                }

                return this._interpolateSegAlt(clipPoints, points, altitude);
            }

            return {
                points: clipPoints,
                altitude: altitude
            };
        };

        _proto._interpolateSegAlt = function _interpolateSegAlt(clipSegs, orig, altitude) {
            if (!Array.isArray(altitude)) {
                var fn = function fn(cc) {
                    return cc.point;
                };

                return {
                    points: clipSegs.map(function(c) {
                        if (Array.isArray(c)) {
                            return c.map(fn);
                        }

                        return c.point;
                    }),
                    altitude: altitude
                };
            }

            var segsWithAlt = interpolateAlt(clipSegs, orig, altitude);
            altitude = [];
            var points = segsWithAlt.map(function(p) {
                if (Array.isArray(p)) {
                    var alt = [];
                    var cp = p.map(function(pp) {
                        alt.push(pp.altitude);
                        return pp.point;
                    });
                    altitude.push(alt);
                    return cp;
                }

                altitude.push(p.altitude);
                return p.point;
            });
            return {
                points: points,
                altitude: altitude
            };
        };

        _proto.getSymbol = function getSymbol() {
            return this.geometry._getInternalSymbol();
        };

        _proto.paint = function paint(extent, context, offset) {
            if (!this.symbolizers) {
                return;
            }

            var renderer = this.getLayer()._getRenderer();

            if (!renderer || !renderer.context && !context) {
                return;
            }

            if (extent && !extent.intersects(this.get2DExtent(renderer.resources, TEMP_PAINT_EXTENT))) {
                return;
            }

            var map = this.getMap();
            var minAltitude = this.getMinAltitude();
            var frustumAlt = map.getFrustumAltitude();

            if (minAltitude && frustumAlt && frustumAlt < minAltitude) {
                return;
            }

            this.containerOffset = offset || map._pointToContainerPoint(renderer.southWest)._add(0, -map.height);

            this._beforePaint();

            var ctx = context || renderer.context;
            var contexts = [ctx, renderer.resources];

            for (var i = this.symbolizers.length - 1; i >= 0; i--) {
                this._prepareShadow(ctx, this.symbolizers[i].symbol);

                this.symbolizers[i].symbolize.apply(this.symbolizers[i], contexts);
            }

            this._afterPaint();

            this._painted = true;

            this._debugSymbolizer.symbolize.apply(this._debugSymbolizer, contexts);
        };

        _proto.getSprite = function getSprite(resources, canvasClass) {
            if (this.geometry.type !== 'Point') {
                return null;
            }

            this._spriting = true;

            if (!this._sprite && this.symbolizers.length > 0) {
                var extent = new PointExtent();
                this.symbolizers.forEach(function(s) {
                    var markerExtent = s.getFixedExtent(resources);

                    extent._combine(markerExtent);
                });
                var origin = extent.getMin().multi(-1);
                var clazz = canvasClass || (this.getMap() ? this.getMap().CanvasClass : null);
                var canvas = Canvas.createCanvas(extent.getWidth(), extent.getHeight(), clazz);
                var bak;

                if (this._renderPoints) {
                    bak = this._renderPoints;
                }

                var ctx = canvas.getContext('2d');
                var contexts = [ctx, resources];

                for (var i = this.symbolizers.length - 1; i >= 0; i--) {
                    var dxdy = this.symbolizers[i].getDxDy();
                    this._renderPoints = {
                        'center': [
                            [origin.add(dxdy)]
                        ]
                    };

                    this._prepareShadow(ctx, this.symbolizers[i].symbol);

                    this.symbolizers[i].symbolize.apply(this.symbolizers[i], contexts);
                }

                if (bak) {
                    this._renderPoints = bak;
                }

                this._sprite = {
                    'canvas': canvas,
                    'offset': extent.getCenter()
                };
            }

            this._spriting = false;
            return this._sprite;
        };

        _proto.isSpriting = function isSpriting() {
            return !!this._spriting;
        };

        _proto.hitTest = function hitTest(cp, tolerance) {
            if (!tolerance || tolerance < 0.5) {
                tolerance = 0.5;
            }

            if (!testCanvas) {
                testCanvas = Canvas.createCanvas(1, 1);
            }

            Canvas.setHitTesting(true);
            testCanvas.width = testCanvas.height = 2 * tolerance;
            var ctx = testCanvas.getContext('2d');
            this._hitPoint = cp.sub(tolerance, tolerance);

            try {
                this.paint(null, ctx, this._hitPoint);
            } catch (e) {
                throw e;
            } finally {
                Canvas.setHitTesting(false);
            }

            delete this._hitPoint;
            var imgData = ctx.getImageData(0, 0, testCanvas.width, testCanvas.height).data;

            for (var i = 3, l = imgData.length; i < l; i += 4) {
                if (imgData[i] > 0) {
                    return true;
                }
            }

            return false;
        };

        _proto.isHitTesting = function isHitTesting() {
            return !!this._hitPoint;
        };

        _proto._prepareShadow = function _prepareShadow(ctx, symbol) {
            if (symbol['shadowBlur']) {
                ctx.shadowBlur = this.isHitTesting() ? 0 : symbol['shadowBlur'];
                ctx.shadowColor = symbol['shadowColor'] || '#000';
                ctx.shadowOffsetX = symbol['shadowOffsetX'] || 0;
                ctx.shadowOffsetY = symbol['shadowOffsetY'] || 0;
            } else if (ctx.shadowBlur) {
                ctx.shadowBlur = null;
                ctx.shadowColor = null;
                ctx.shadowOffsetX = null;
                ctx.shadowOffsetY = null;
            }
        };

        _proto._eachSymbolizer = function _eachSymbolizer(fn, context) {
            if (!this.symbolizers) {
                return;
            }

            if (!context) {
                context = this;
            }

            for (var i = this.symbolizers.length - 1; i >= 0; i--) {
                fn.apply(context, [this.symbolizers[i]]);
            }
        };

        _proto.get2DExtent = function get2DExtent(resources, out) {
            this._verifyProjection();

            var map = this.getMap();
            resources = resources || this.getLayer()._getRenderer().resources;
            var zoom = map.getZoom();

            var isDynamicSize = this._isDynamicSize();

            if (!this._extent2D || this._extent2D._zoom !== zoom || !this._fixedExtent) {
                if (this._extent2D && this._extent2D._zoom !== zoom) {
                    delete this._extent2D;
                }

                if (this.symbolizers) {
                    if (!this._extent2D) {
                        this._extent2D = this._computeExtent2D(new PointExtent());
                        this._extent2D._zoom = zoom;
                    }

                    if (!this._fixedExtent) {
                        this._fixedExtent = this._computeFixedExtent(resources, new PointExtent());
                    }
                }
            }

            if (!this._extent2D) {
                if (isDynamicSize) {
                    delete this._fixedExtent;
                }

                return null;
            }

            var _this$_fixedExtent = this._fixedExtent,
                xmin = _this$_fixedExtent.xmin,
                ymin = _this$_fixedExtent.ymin,
                xmax = _this$_fixedExtent.xmax,
                ymax = _this$_fixedExtent.ymax;

            if (isDynamicSize) {
                delete this._fixedExtent;
            }

            TEMP_FIXED_EXTENT.set(xmin, -ymax, xmax, -ymin);

            if (out) {
                out.set(this._extent2D['xmin'], this._extent2D['ymin'], this._extent2D['xmax'], this._extent2D['ymax']);

                out._add(TEMP_FIXED_EXTENT);

                return out;
            }

            return this._extent2D.add(TEMP_FIXED_EXTENT);
        };

        _proto._computeExtent2D = function _computeExtent2D(extent) {
            for (var i = this.symbolizers.length - 1; i >= 0; i--) {
                var symbolizer = this.symbolizers[i];

                extent._combine(symbolizer.get2DExtent());
            }

            return extent;
        };

        _proto._computeFixedExtent = function _computeFixedExtent(resources, extent) {
            for (var i = this.symbolizers.length - 1; i >= 0; i--) {
                var symbolizer = this.symbolizers[i];

                if (symbolizer.getFixedExtent) {
                    extent._combine(symbolizer.getFixedExtent(resources));
                }
            }

            return extent;
        };

        _proto._isDynamicSize = function _isDynamicSize() {
            for (var i = this.symbolizers.length - 1; i >= 0; i--) {
                var symbolizer = this.symbolizers[i];

                if (symbolizer.isDynamicSize()) {
                    return true;
                }
            }

            return false;
        };

        _proto.getContainerExtent = function getContainerExtent(out) {
            if (this._aboveCamera()) {
                return null;
            }

            this._verifyProjection();

            var map = this.getMap();
            var zoom = map.getZoom();
            var glScale = map._glScale;

            if (!this._extent2D || this._extent2D._zoom !== zoom) {
                this.get2DExtent(null, TEMP_EXTENT$1);
            }

            var altitude = this.getMinAltitude();

            var extent = this._extent2D.convertTo(function(c) {
                return map._pointToContainerPoint(c, zoom, altitude / glScale, TEMP_POINT0$2);
            }, out);

            var maxAltitude = this.getMaxAltitude();

            if (maxAltitude !== altitude) {
                var extent2 = this._extent2D.convertTo(function(c) {
                    return map._pointToContainerPoint(c, zoom, maxAltitude / glScale, TEMP_POINT0$2);
                }, TEMP_EXTENT$1);

                extent._combine(extent2);
            }

            var layer = this.geometry.getLayer();

            if (this.geometry.type === 'LineString' && maxAltitude && layer.options['drawAltitude']) {
                var groundExtent = this._extent2D.convertTo(function(c) {
                    return map._pointToContainerPoint(c, zoom, 0, TEMP_POINT0$2);
                }, TEMP_EXTENT$1);

                extent._combine(groundExtent);
            }

            if (extent) {
                extent._add(this._fixedExtent || this._computeFixedExtent(null, new PointExtent()));
            }

            var smoothness = this.geometry.options['smoothness'];

            if (smoothness) {
                extent._expand(extent.getWidth() * 0.15);
            }

            return extent;
        };

        _proto._aboveCamera = function _aboveCamera() {
            var altitude = this.getMinAltitude();
            var map = this.getMap();
            var frustumAlt = map.getFrustumAltitude();
            return altitude && frustumAlt && frustumAlt < altitude;
        };

        _proto.getFixedExtent = function getFixedExtent() {
            var map = this.getMap();
            var zoom = map.getZoom();

            if (this._isDynamicSize()) {
                return this._computeFixedExtent(null, new PointExtent());
            }

            if (!this._extent2D || this._extent2D._zoom !== zoom) {
                this.get2DExtent(null, TEMP_FIXED_EXTENT);
            }

            return this._fixedExtent;
        };

        _proto.setZIndex = function setZIndex(change) {
            this._eachSymbolizer(function(symbolizer) {
                symbolizer.setZIndex(change);
            });
        };

        _proto.show = function show() {
            if (!this._painted) {
                var layer = this.getLayer();

                if (!layer.isCanvasRender()) {
                    this.paint();
                }
            } else {
                this.removeCache();

                this._eachSymbolizer(function(symbolizer) {
                    symbolizer.show();
                });
            }
        };

        _proto.hide = function hide() {
            this._eachSymbolizer(function(symbolizer) {
                symbolizer.hide();
            });
        };

        _proto.repaint = function repaint() {
            this._altAtGLZoom = this._getGeometryAltitude();
            this.removeCache();
            var layer = this.getLayer();

            if (!layer) {
                return;
            }

            var renderer = layer.getRenderer();

            if (!renderer || !renderer.setToRedraw()) {
                return;
            }

            renderer.setToRedraw();
        };

        _proto.refreshSymbol = function refreshSymbol() {
            this.removeCache();

            this._removeSymbolizers();

            this.symbolizers = this._createSymbolizers();
        };

        _proto.remove = function remove() {
            this.removeCache();

            this._removeSymbolizers();
        };

        _proto._removeSymbolizers = function _removeSymbolizers() {
            this._eachSymbolizer(function(symbolizer) {
                delete symbolizer.painter;
                symbolizer.remove();
            });

            delete this.symbolizers;
        };

        _proto.removeCache = function removeCache() {
            delete this._renderPoints;
            delete this._paintParams;
            delete this._sprite;
            delete this._extent2D;
            delete this._fixedExtent;
            delete this._cachedParams;
            delete this._unsimpledParams;

            if (this.geometry) {
                delete this.geometry[TextMarkerSymbolizer.CACHE_KEY];
            }
        };

        _proto.getAltitude = function getAltitude() {
            var propAlt = this.geometry.getAltitude();

            if (propAlt !== this._propAlt) {
                this._altAtGLZoom = this._getGeometryAltitude();
            }

            if (!this._altAtGLZoom) {
                return 0;
            }

            return this._altAtGLZoom;
        };

        _proto.getMinAltitude = function getMinAltitude() {
            if (!this.minAltitude) {
                return 0;
            }

            return this.minAltitude;
        };

        _proto.getMaxAltitude = function getMaxAltitude() {
            if (!this.maxAltitude) {
                return 0;
            }

            return this.maxAltitude;
        };

        _proto._getGeometryAltitude = function _getGeometryAltitude() {
            var _this2 = this;

            var map = this.getMap();

            if (!map) {
                return 0;
            }

            var altitude = this.geometry.getAltitude();
            this._propAlt = altitude;

            if (!altitude) {
                this.minAltitude = this.maxAltitude = 0;
                return 0;
            }

            var center = this.geometry.getCenter();

            if (!center) {
                return 0;
            }

            if (Array.isArray(altitude)) {
                this.minAltitude = Number.MAX_VALUE;
                this.maxAltitude = Number.MIN_VALUE;
                return altitude.map(function(alt) {
                    var a = _this2._meterToPoint(center, alt);

                    if (a < _this2.minAltitude) {
                        _this2.minAltitude = a;
                    }

                    if (a > _this2.maxAltitude) {
                        _this2.maxAltitude = a;
                    }

                    return a;
                });
            } else {
                this.minAltitude = this.maxAltitude = this._meterToPoint(center, altitude);
                return this.minAltitude;
            }
        };

        _proto._meterToPoint = function _meterToPoint(center, altitude) {
            var map = this.getMap();
            var z = map.getGLZoom();
            return map.distanceToPoint(altitude, 0, z, center).x * sign(altitude);
        };

        _proto._verifyProjection = function _verifyProjection() {
            var projection = this.geometry._getProjection();

            if (this._projCode && this._projCode !== projection.code) {
                this.removeCache();
            }

            this._projCode = projection.code;
        };

        _proto._beforePaint = function _beforePaint() {
            var textcache = this.geometry[TextMarkerSymbolizer.CACHE_KEY];

            if (!textcache) {
                return;
            }

            for (var p in textcache) {
                if (hasOwn(textcache, p)) {
                    textcache[p].active = false;
                }
            }
        };

        _proto._afterPaint = function _afterPaint() {
            var textcache = this.geometry[TextMarkerSymbolizer.CACHE_KEY];

            if (!textcache) {
                return;
            }

            for (var p in textcache) {
                if (hasOwn(textcache, p)) {
                    if (!textcache[p].active) {
                        delete textcache[p];
                    }
                }
            }
        };

        return Painter;
    }(Class);

    function interpolateAlt(points, orig, altitude) {
        if (!Array.isArray(altitude)) {
            return points;
        }

        var parts = [];

        for (var i = 0, l = points.length; i < l; i++) {
            if (Array.isArray(points[i])) {
                parts.push(interpolateAlt(points[i], orig, altitude));
            } else {
                var p = points[i];

                if (!p.point.equals(orig[p.index])) {
                    var w0 = void 0,
                        w1 = void 0;

                    if (p.index === 0) {
                        w0 = p.index;
                        w1 = p.index + 1;
                    } else {
                        w0 = p.index - 1;
                        w1 = p.index;
                    }

                    var t0 = p.point.distanceTo(orig[w1]);
                    var t = t0 / (t0 + orig[w0].distanceTo(p.point));
                    var alt = interpolate(altitude[w0], altitude[w1], 1 - t);
                    p.altitude = alt;
                    parts.push(p);
                } else {
                    p.altitude = altitude[p.index];
                    parts.push(p);
                }
            }
        }

        return parts;
    }

    var TEMP_EXTENT$2 = new PointExtent();

    var CollectionPainter = function(_Class) {
        _inheritsLoose(CollectionPainter, _Class);

        function CollectionPainter(geometry, isMask) {
            var _this;

            _this = _Class.call(this) || this;
            _this.geometry = geometry;
            _this.isMask = isMask;
            return _this;
        }

        var _proto = CollectionPainter.prototype;

        _proto._eachPainter = function _eachPainter(fn) {
            var geometries = this.geometry.getGeometries();
            var painter;

            for (var i = 0, len = geometries.length; i < len; i++) {
                painter = this.isMask ? geometries[i]._getMaskPainter() : geometries[i]._getPainter();

                if (!painter) {
                    continue;
                }

                if (painter) {
                    if (fn.call(this, painter) === false) {
                        break;
                    }
                }
            }
        };

        _proto.paint = function paint(extent) {
            if (!this.geometry) {
                return;
            }

            this._eachPainter(function(painter) {
                painter.paint(extent);
            });
        };

        _proto.get2DExtent = function get2DExtent(resources, out) {
            if (out) {
                out.set(null, null, null, null);
            }

            var extent = out || new PointExtent();

            this._eachPainter(function(painter) {
                extent = extent._combine(painter.get2DExtent(resources, TEMP_EXTENT$2));
            });

            return extent;
        };

        _proto.getContainerExtent = function getContainerExtent() {
            var extent = new PointExtent();

            this._eachPainter(function(painter) {
                extent = extent.combine(painter.getContainerExtent());
            });

            return extent;
        };

        _proto.remove = function remove() {
            var args = arguments;

            this._eachPainter(function(painter) {
                painter.remove.apply(painter, args);
            });
        };

        _proto.setZIndex = function setZIndex() {
            var args = arguments;

            this._eachPainter(function(painter) {
                painter.setZIndex.apply(painter, args);
            });
        };

        _proto.show = function show() {
            var args = arguments;

            this._eachPainter(function(painter) {
                painter.show.apply(painter, args);
            });
        };

        _proto.hide = function hide() {
            var args = arguments;

            this._eachPainter(function(painter) {
                painter.hide.apply(painter, args);
            });
        };

        _proto.repaint = function repaint() {
            var args = arguments;

            this._eachPainter(function(painter) {
                painter.repaint.apply(painter, args);
            });
        };

        _proto.refreshSymbol = function refreshSymbol() {
            var args = arguments;

            this._eachPainter(function(painter) {
                painter.refreshSymbol.apply(painter, args);
            });
        };

        _proto.hasPoint = function hasPoint() {
            var result = false;

            this._eachPainter(function(painter) {
                if (painter.hasPoint()) {
                    result = true;
                    return false;
                }

                return true;
            });

            return result;
        };

        _proto.getMinAltitude = function getMinAltitude() {
            var first = true;
            var result = 0;

            this._eachPainter(function(painter) {
                var alt = painter.getMinAltitude();

                if (first || alt < result) {
                    first = false;
                    result = alt;
                }
            });

            return result;
        };

        _proto.getMaxAltitude = function getMaxAltitude() {
            var result = 0;

            this._eachPainter(function(painter) {
                var alt = painter.getMaxAltitude();

                if (alt > result) {
                    result = alt;
                }
            });

            return result;
        };

        return CollectionPainter;
    }(Class);

    var DefaultSpatialReference = {
        'EPSG:3857': {
            'resolutions': function() {
                var resolutions = [];
                var d = 2 * 6378137 * Math.PI;

                for (var i = 0; i < 21; i++) {
                    resolutions[i] = d / (256 * Math.pow(2, i));
                }

                return resolutions;
            }(),
            'fullExtent': {
                'top': 6378137 * Math.PI,
                'left': -6378137 * Math.PI,
                'bottom': -6378137 * Math.PI,
                'right': 6378137 * Math.PI
            }
        },
        'EPSG:4326': {
            'fullExtent': {
                'top': 90,
                'left': -180,
                'bottom': -90,
                'right': 180
            },
            'resolutions': function() {
                var resolutions = [];

                for (var i = 0; i < 20; i++) {
                    resolutions[i] = 180 / (Math.pow(2, i) * 128);
                }

                return resolutions;
            }()
        },
        'BAIDU': {
            'resolutions': function() {
                var res = Math.pow(2, 18);
                var resolutions = [];

                for (var i = 0; i < 20; i++) {
                    resolutions[i] = res;
                    res *= 0.5;
                }

                return resolutions;
            }(),
            'fullExtent': {
                'top': 33554432,
                'left': -33554432,
                'bottom': -33554432,
                'right': 33554432
            }
        },
        'IDENTITY': {
            'resolutions': function() {
                var res = Math.pow(2, 8);
                var resolutions = [];

                for (var i = 0; i < 18; i++) {
                    resolutions[i] = res;
                    res *= 0.5;
                }

                return resolutions;
            }(),
            'fullExtent': {
                'top': 200000,
                'left': -200000,
                'bottom': -200000,
                'right': 200000
            }
        }
    };
    DefaultSpatialReference['EPSG:4490'] = DefaultSpatialReference['EPSG:4326'];

    var SpatialReference = function() {
        function SpatialReference(options) {
            if (options === void 0) {
                options = {};
            }

            this.options = options;

            this._initSpatialRef();
        }

        SpatialReference.getProjectionInstance = function getProjectionInstance(prjName) {
            if (!prjName) {
                return null;
            }

            if (isObject(prjName)) {
                return prjName;
            }

            prjName = (prjName + '').toLowerCase();

            for (var p in projections) {
                if (hasOwn(projections, p)) {
                    var code = projections[p]['code'];

                    if (code && code.toLowerCase() === prjName) {
                        return projections[p];
                    }
                }
            }

            return null;
        };

        SpatialReference.equals = function equals(sp1, sp2) {
            if (!sp1 && !sp2) {
                return true;
            } else if (!sp1 || !sp2) {
                return false;
            }

            if (sp1.projection !== sp2.projection) {
                return false;
            }

            var f1 = sp1.fullExtent,
                f2 = sp2.fullExtent;

            if (f1 && !f2 || !f1 && f2) {
                return false;
            }

            if (f1 && f2) {
                if (f1.top !== f2.top || f1.bottom !== f2.bottom || f1.left !== f2.left || f1.right !== f2.right) {
                    return false;
                }
            }

            var r1 = sp1.resolutions,
                r2 = sp2.resolutions;

            if (r1 && r2) {
                if (r1.length !== r2.length) {
                    return false;
                }

                for (var i = 0; i < r1.length; i++) {
                    if (r1[i] !== r2[i]) {
                        return false;
                    }
                }
            }

            return true;
        };

        var _proto = SpatialReference.prototype;

        _proto._initSpatialRef = function _initSpatialRef() {
            var projection = this.options['projection'];

            if (projection) {
                projection = SpatialReference.getProjectionInstance(projection);
            } else {
                projection = DEFAULT$1;
            }

            if (!projection) {
                throw new Error('must provide a valid projection in map\'s spatial reference.');
            }

            projection = extend({}, Common, projection);

            if (!projection.measureLength) {
                extend(projection, Measurer.DEFAULT);
            }

            this._projection = projection;
            var defaultSpatialRef,
                resolutions = this.options['resolutions'];

            if (!resolutions) {
                if (projection['code']) {
                    defaultSpatialRef = DefaultSpatialReference[projection['code']];

                    if (defaultSpatialRef) {
                        resolutions = defaultSpatialRef['resolutions'];
                        this.isEPSG = projection['code'] !== 'IDENTITY';
                    }
                }

                if (!resolutions) {
                    throw new Error('must provide valid resolutions in map\'s spatial reference.');
                }
            }

            this._resolutions = resolutions;
            var fullExtent = this.options['fullExtent'];

            if (!fullExtent) {
                if (projection['code']) {
                    defaultSpatialRef = DefaultSpatialReference[projection['code']];

                    if (defaultSpatialRef) {
                        fullExtent = defaultSpatialRef['fullExtent'];
                    }
                }

                if (!fullExtent) {
                    throw new Error('must provide a valid fullExtent in map\'s spatial reference.');
                }
            }

            if (!isNil(fullExtent['left'])) {
                this._fullExtent = new Extent(new Coordinate(fullExtent['left'], fullExtent['top']), new Coordinate(fullExtent['right'], fullExtent['bottom']));
            } else {
                this._fullExtent = new Extent(fullExtent);
                fullExtent['left'] = fullExtent['xmin'];
                fullExtent['right'] = fullExtent['xmax'];
                fullExtent['top'] = fullExtent['ymax'];
                fullExtent['bottom'] = fullExtent['ymin'];
            }

            if (isNil(fullExtent['top']) || isNil(fullExtent['bottom']) || isNil(fullExtent['left']) || isNil(fullExtent['right'])) {
                throw new Error('must provide valid top/bottom/left/right in fullExtent.');
            }

            extend(this._fullExtent, fullExtent);
            this._projection.fullExtent = fullExtent;
            var a = fullExtent['right'] >= fullExtent['left'] ? 1 : -1,
                b = fullExtent['top'] >= fullExtent['bottom'] ? -1 : 1;
            this._transformation = new Transformation([a, b, 0, 0]);
        };

        _proto.getResolutions = function getResolutions() {
            return this._resolutions || [];
        };

        _proto.getResolution = function getResolution(zoom) {
            var z = zoom | 0;

            if (z < 0) {
                z = 0;
            } else if (z > this._resolutions.length - 1) {
                z = this._resolutions.length - 1;
            }

            var res = this._resolutions[z];

            if (z !== zoom && zoom > 0 && z < this._resolutions.length - 1) {
                var next = this._resolutions[z + 1];
                return res + (next - res) * (zoom - z);
            }

            return res;
        };

        _proto.getProjection = function getProjection() {
            return this._projection;
        };

        _proto.getFullExtent = function getFullExtent() {
            return this._fullExtent;
        };

        _proto.getTransformation = function getTransformation() {
            return this._transformation;
        };

        _proto.getMinZoom = function getMinZoom() {
            for (var i = 0; i < this._resolutions.length; i++) {
                if (!isNil(this._resolutions[i])) {
                    return i;
                }
            }

            return 0;
        };

        _proto.getMaxZoom = function getMaxZoom() {
            for (var i = this._resolutions.length - 1; i >= 0; i--) {
                if (!isNil(this._resolutions[i])) {
                    return i;
                }
            }

            return this._resolutions.length - 1;
        };

        _proto.getZoomDirection = function getZoomDirection() {
            return sign(this._resolutions[this.getMinZoom()] - this._resolutions[this.getMaxZoom()]);
        };

        _proto.toJSON = function toJSON() {
            if (!this.json) {
                this.json = {
                    'resolutions': this._resolutions,
                    'fullExtent': {
                        'top': this._fullExtent.top,
                        'left': this._fullExtent.left,
                        'bottom': this._fullExtent.bottom,
                        'right': this._fullExtent.right
                    },
                    'projection': this._projection.code
                };
            }

            return this.json;
        };

        return SpatialReference;
    }();

    var options = {
        'id': null,
        'visible': true,
        'interactive': true,
        'editable': true,
        'cursor': null,
        'defaultProjection': 'EPSG:4326'
    };

    var Geometry = function(_JSONAble) {
        _inheritsLoose(Geometry, _JSONAble);

        function Geometry(options) {
            var _this;

            var opts = extend({}, options);
            var symbol = opts['symbol'];
            var properties = opts['properties'];
            var id = opts['id'];
            delete opts['symbol'];
            delete opts['id'];
            delete opts['properties'];
            _this = _JSONAble.call(this, opts) || this;

            if (symbol) {
                _this.setSymbol(symbol);
            }

            if (properties) {
                _this.setProperties(properties);
            }

            if (!isNil(id)) {
                _this.setId(id);
            }

            return _this;
        }

        var _proto = Geometry.prototype;

        _proto.getFirstCoordinate = function getFirstCoordinate() {
            if (this.type === 'GeometryCollection') {
                var geometries = this.getGeometries();

                if (!geometries.length) {
                    return null;
                }

                return geometries[0].getFirstCoordinate();
            }

            var coordinates = this.getCoordinates();

            if (!Array.isArray(coordinates)) {
                return coordinates;
            }

            do {
                coordinates = coordinates[0];
            } while (Array.isArray(coordinates) && coordinates.length > 0);

            return coordinates;
        };

        _proto.getLastCoordinate = function getLastCoordinate() {
            if (this.type === 'GeometryCollection') {
                var geometries = this.getGeometries();

                if (!geometries.length) {
                    return null;
                }

                return geometries[geometries.length - 1].getLastCoordinate();
            }

            var coordinates = this.getCoordinates();

            if (!Array.isArray(coordinates)) {
                return coordinates;
            }

            do {
                coordinates = coordinates[coordinates.length - 1];
            } while (Array.isArray(coordinates) && coordinates.length > 0);

            return coordinates;
        };

        _proto.addTo = function addTo(layer, fitview) {
            layer.addGeometry(this, fitview);
            return this;
        };

        _proto.getLayer = function getLayer() {
            if (!this._layer) {
                return null;
            }

            return this._layer;
        };

        _proto.getMap = function getMap() {
            if (!this._layer) {
                return null;
            }

            return this._layer.getMap();
        };

        _proto.getId = function getId() {
            return this._id;
        };

        _proto.setId = function setId(id) {
            var oldId = this.getId();
            this._id = id;

            this._fireEvent('idchange', {
                'old': oldId,
                'new': id
            });

            return this;
        };

        _proto.getProperties = function getProperties() {
            if (!this.properties) {
                if (this._getParent()) {
                    return this._getParent().getProperties();
                }

                return null;
            }

            return this.properties;
        };

        _proto.setProperties = function setProperties(properties) {
            var old = this.properties;
            this.properties = isObject(properties) ? extend({}, properties) : properties;

            this._repaint();

            this._fireEvent('propertieschange', {
                'old': old,
                'new': properties
            });

            return this;
        };

        _proto.getType = function getType() {
            return this.type;
        };

        _proto.getSymbol = function getSymbol() {
            var s = this._symbol;

            if (s) {
                if (!Array.isArray(s)) {
                    return extend({}, s);
                } else {
                    return extendSymbol(s);
                }
            }

            return null;
        };

        _proto.setSymbol = function setSymbol(symbol) {
            this._symbol = this._prepareSymbol(symbol);
            this.onSymbolChanged();
            return this;
        };

        _proto.updateSymbol = function updateSymbol(props) {
            if (!props) {
                return this;
            }

            var s = this._getSymbol();

            if (s) {
                s = extendSymbol(s, props);
            } else {
                s = extendSymbol(this._getInternalSymbol(), props);
            }

            this._eventSymbolProperties = props;
            return this.setSymbol(s);
        };

        _proto.getCenter = function getCenter() {
            return this._computeCenter(this._getMeasurer());
        };

        _proto.getExtent = function getExtent() {
            var prjExt = this._getPrjExtent();

            var projection = this._getProjection();

            if (prjExt && projection) {
                var min = projection.unproject(new Coordinate(prjExt['xmin'], prjExt['ymin'])),
                    max = projection.unproject(new Coordinate(prjExt['xmax'], prjExt['ymax']));
                return new Extent(min, max, projection);
            } else {
                return this._computeExtent(this._getMeasurer());
            }
        };

        _proto.getContainerExtent = function getContainerExtent(out) {
            var painter = this._getPainter();

            return painter ? painter.getContainerExtent(out) : null;
        };

        _proto.getSize = function getSize() {
            var extent = this.getContainerExtent();
            return extent ? extent.getSize() : null;
        };

        _proto.containsPoint = function containsPoint(containerPoint, t) {
            if (!this.getMap()) {
                throw new Error('The geometry is required to be added on a map to perform "containsPoint".');
            }

            if (containerPoint instanceof Coordinate) {
                containerPoint = this.getMap().coordToContainerPoint(containerPoint);
            }

            return this._containsPoint(containerPoint, t);
        };

        _proto._containsPoint = function _containsPoint(containerPoint, t) {
            var painter = this._getPainter();

            if (!painter) {
                return false;
            }

            if (isNil(t) && this._hitTestTolerance) {
                t = this._hitTestTolerance();
            }

            return painter.hitTest(containerPoint, t);
        };

        _proto.show = function show() {
            this.options['visible'] = true;

            if (this.getMap()) {
                var painter = this._getPainter();

                if (painter) {
                    painter.show();
                }

                this._fireEvent('show');
            }

            return this;
        };

        _proto.hide = function hide() {
            this.options['visible'] = false;

            if (this.getMap()) {
                this.onHide();

                var painter = this._getPainter();

                if (painter) {
                    painter.hide();
                }

                this._fireEvent('hide');
            }

            return this;
        };

        _proto.isVisible = function isVisible() {
            if (!this.options['visible']) {
                return false;
            }

            var symbol = this._getInternalSymbol();

            if (!symbol) {
                return true;
            }

            if (Array.isArray(symbol)) {
                if (!symbol.length) {
                    return true;
                }

                for (var i = 0, l = symbol.length; i < l; i++) {
                    if (isNil(symbol[i]['opacity']) || symbol[i]['opacity'] > 0) {
                        return true;
                    }
                }

                return false;
            } else {
                return isNil(symbol['opacity']) || isNumber(symbol['opacity']) && symbol['opacity'] > 0;
            }
        };

        _proto.getZIndex = function getZIndex() {
            return this.options['zIndex'] || 0;
        };

        _proto.setZIndex = function setZIndex(zIndex) {
            var old = this.options['zIndex'];
            this.options['zIndex'] = zIndex;

            this._fireEvent('zindexchange', {
                'old': old,
                'new': zIndex
            });

            return this;
        };

        _proto.setZIndexSilently = function setZIndexSilently(zIndex) {
            this.options['zIndex'] = zIndex;
            return this;
        };

        _proto.bringToFront = function bringToFront() {
            var layer = this.getLayer();

            if (!layer || !layer.getGeoMaxZIndex) {
                return this;
            }

            var topZ = layer.getGeoMaxZIndex();
            this.setZIndex(topZ + 1);
            return this;
        };

        _proto.bringToBack = function bringToBack() {
            var layer = this.getLayer();

            if (!layer || !layer.getGeoMinZIndex) {
                return this;
            }

            var bottomZ = layer.getGeoMinZIndex();
            this.setZIndex(bottomZ - 1);
            return this;
        };

        _proto.translate = function translate(x, y) {
            if (isNil(x)) {
                return this;
            }

            var offset = new Coordinate(x, y);

            if (offset.x === 0 && offset.y === 0) {
                return this;
            }

            var coordinates = this.getCoordinates();

            if (coordinates) {
                if (Array.isArray(coordinates)) {
                    var translated = forEachCoord(coordinates, function(coord) {
                        return coord.add(offset);
                    });
                    this.setCoordinates(translated);
                } else {
                    this.setCoordinates(coordinates.add(offset));
                }
            }

            return this;
        };

        _proto.flash = function flash$$1(interval, count, cb, context) {
            return flash.call(this, interval, count, cb, context);
        };

        _proto.copy = function copy() {
            var json = this.toJSON();
            var ret = Geometry.fromJSON(json);
            ret.options['visible'] = true;
            return ret;
        };

        _proto.remove = function remove() {
            var layer = this.getLayer();

            if (!layer) {
                return this;
            }

            this._fireEvent('removestart');

            this._unbind();

            this._fireEvent('removeend');

            this._fireEvent('remove');

            return this;
        };

        _proto.toGeoJSONGeometry = function toGeoJSONGeometry() {
            var gJson = this._exportGeoJSONGeometry();

            return gJson;
        };

        _proto.toGeoJSON = function toGeoJSON(opts) {
            if (!opts) {
                opts = {};
            }

            var feature = {
                'type': 'Feature',
                'geometry': null
            };

            if (isNil(opts['geometry']) || opts['geometry']) {
                var geoJSON = this._exportGeoJSONGeometry();

                feature['geometry'] = geoJSON;
            }

            var id = this.getId();

            if (!isNil(id)) {
                feature['id'] = id;
            }

            var properties;

            if (isNil(opts['properties']) || opts['properties']) {
                properties = this._exportProperties();
            }

            feature['properties'] = properties;
            return feature;
        };

        _proto.toJSON = function toJSON(options) {
            if (!options) {
                options = {};
            }

            var json = this._toJSON(options);

            var other = this._exportGraphicOptions(options);

            extend(json, other);
            return json;
        };

        _proto.getLength = function getLength() {
            return this._computeGeodesicLength(this._getMeasurer());
        };

        _proto.getArea = function getArea() {
            return this._computeGeodesicArea(this._getMeasurer());
        };

        _proto.rotate = function rotate(angle, pivot) {
            if (this.type === 'GeometryCollection') {
                var geometries = this.getGeometries();
                geometries.forEach(function(g) {
                    return g.rotate(angle, pivot);
                });
                return this;
            }

            if (!pivot) {
                pivot = this.getCenter();
            } else {
                pivot = new Coordinate(pivot);
            }

            var measurer = this._getMeasurer();

            var coordinates = this.getCoordinates();

            if (!Array.isArray(coordinates)) {
                if (pivot.x !== coordinates.x || pivot.y !== coordinates.y) {
                    var c = measurer._rotate(coordinates, pivot, angle);

                    this.setCoordinates(c);
                }

                return this;
            }

            forEachCoord(coordinates, function(c) {
                return measurer._rotate(c, pivot, angle);
            });
            this.setCoordinates(coordinates);
            return this;
        };

        _proto._getConnectPoints = function _getConnectPoints() {
            return [this.getCenter()];
        };

        _proto._initOptions = function _initOptions(options) {
            var opts = extend({}, options);
            var symbol = opts['symbol'];
            var properties = opts['properties'];
            var id = opts['id'];
            delete opts['symbol'];
            delete opts['id'];
            delete opts['properties'];
            this.setOptions(opts);

            if (symbol) {
                this.setSymbol(symbol);
            }

            if (properties) {
                this.setProperties(properties);
            }

            if (!isNil(id)) {
                this.setId(id);
            }
        };

        _proto._bindLayer = function _bindLayer(layer) {
            if (this.getLayer()) {
                throw new Error('Geometry cannot be added to two or more layers at the same time.');
            }

            this._layer = layer;

            this._clearCache();
        };

        _proto._prepareSymbol = function _prepareSymbol(symbol) {
            if (Array.isArray(symbol)) {
                var cookedSymbols = [];

                for (var i = 0; i < symbol.length; i++) {
                    cookedSymbols.push(convertResourceUrl(this._checkAndCopySymbol(symbol[i])));
                }

                return cookedSymbols;
            } else if (symbol) {
                symbol = this._checkAndCopySymbol(symbol);
                return convertResourceUrl(symbol);
            }

            return null;
        };

        _proto._checkAndCopySymbol = function _checkAndCopySymbol(symbol) {
            var s = {};

            for (var i in symbol) {
                if (NUMERICAL_PROPERTIES[i] && isString(symbol[i])) {
                    s[i] = +symbol[i];
                } else {
                    s[i] = symbol[i];
                }
            }

            return s;
        };

        _proto._getSymbol = function _getSymbol() {
            return this._symbol;
        };

        _proto._setExternSymbol = function _setExternSymbol(symbol) {
            this._eventSymbolProperties = symbol;
            this._externSymbol = this._prepareSymbol(symbol);
            this.onSymbolChanged();
            return this;
        };

        _proto._getInternalSymbol = function _getInternalSymbol() {
            if (this._symbol) {
                return this._symbol;
            } else if (this._externSymbol) {
                return this._externSymbol;
            } else if (this.options['symbol']) {
                return this.options['symbol'];
            }

            return null;
        };

        _proto._getPrjExtent = function _getPrjExtent() {
            var p = this._getProjection();

            this._verifyProjection();

            if (!this._extent && p) {
                this._extent = this._computePrjExtent(p);
            }

            return this._extent;
        };

        _proto._unbind = function _unbind() {
            var layer = this.getLayer();

            if (!layer) {
                return;
            }

            if (this._animPlayer) {
                this._animPlayer.finish();
            }

            this._clearHandlers();

            this._unbindMenu();

            this._unbindInfoWindow();

            if (this.isEditing()) {
                this.endEdit();
            }

            this._removePainter();

            if (this.onRemove) {
                this.onRemove();
            }

            if (layer.onRemoveGeometry) {
                layer.onRemoveGeometry(this);
            }

            delete this._layer;
            delete this._internalId;
            delete this._extent;
        };

        _proto._getInternalId = function _getInternalId() {
            return this._internalId;
        };

        _proto._setInternalId = function _setInternalId(id) {
            this._internalId = id;
        };

        _proto._getMeasurer = function _getMeasurer() {
            if (this._getProjection()) {
                return this._getProjection();
            }

            return SpatialReference.getProjectionInstance(this.options['defaultProjection']);
        };

        _proto._getProjection = function _getProjection() {
            var map = this.getMap();

            if (map) {
                return map.getProjection();
            }

            return null;
        };

        _proto._verifyProjection = function _verifyProjection() {
            var projection = this._getProjection();

            if (this._projCode && projection && this._projCode !== projection.code) {
                this._clearProjection();
            }

            this._projCode = projection ? projection.code : this._projCode;
        };

        _proto._getExternalResources = function _getExternalResources() {
            var symbol = this._getInternalSymbol();

            return getExternalResources(symbol);
        };

        _proto._getPainter = function _getPainter() {
            var layer = this.getLayer();

            if (!this._painter && layer) {
                if (GEOMETRY_COLLECTION_TYPES.indexOf(this.type) !== -1) {
                    if (layer.constructor.getCollectionPainterClass) {
                        var clazz = layer.constructor.getCollectionPainterClass();
                        this._painter = new clazz(this);
                    }
                } else if (layer.constructor.getPainterClass) {
                    var _clazz = layer.constructor.getPainterClass();

                    this._painter = new _clazz(this);
                }
            }

            return this._painter;
        };

        _proto._getMaskPainter = function _getMaskPainter() {
            if (this._maskPainter) {
                return this._maskPainter;
            }

            this._maskPainter = this.getGeometries && this.getGeometries() ? new CollectionPainter(this, true) : new Painter(this);
            return this._maskPainter;
        };

        _proto._removePainter = function _removePainter() {
            if (this._painter) {
                this._painter.remove();
            }

            delete this._painter;
        };

        _proto._paint = function _paint(extent) {
            if (this._painter) {
                this._painter.paint(extent);
            }
        };

        _proto._clearCache = function _clearCache() {
            delete this._extent;
        };

        _proto._clearProjection = function _clearProjection() {
            delete this._extent;
        };

        _proto._repaint = function _repaint() {
            if (this._painter) {
                this._painter.repaint();
            }
        };

        _proto.onHide = function onHide() {
            this.closeMenu();
            this.closeInfoWindow();
        };

        _proto.onShapeChanged = function onShapeChanged() {
            this._clearCache();

            this._repaint();

            this._fireEvent('shapechange');
        };

        _proto.onPositionChanged = function onPositionChanged() {
            this._clearCache();

            this._repaint();

            this._fireEvent('positionchange');
        };

        _proto.onSymbolChanged = function onSymbolChanged() {
            if (this._painter) {
                this._painter.refreshSymbol();
            }

            var e = {};

            if (this._eventSymbolProperties) {
                e.properties = extend({}, this._eventSymbolProperties);
                delete this._eventSymbolProperties;
            }

            this._fireEvent('symbolchange', e);
        };

        _proto.onConfig = function onConfig(conf) {
            var properties;

            if (conf['properties']) {
                properties = conf['properties'];
                delete conf['properties'];
            }

            var needRepaint = false;

            for (var p in conf) {
                if (conf.hasOwnProperty(p)) {
                    var prefix = p.slice(0, 5);

                    if (prefix === 'arrow' || prefix === 'smoot') {
                        needRepaint = true;
                        break;
                    }
                }
            }

            if (properties) {
                this.setProperties(properties);

                this._repaint();
            } else if (needRepaint) {
                this._repaint();
            }
        };

        _proto._setParent = function _setParent(geometry) {
            if (geometry) {
                this._parent = geometry;
            }
        };

        _proto._getParent = function _getParent() {
            return this._parent;
        };

        _proto._fireEvent = function _fireEvent(eventName, param) {
            if (this.getLayer() && this.getLayer()._onGeometryEvent) {
                if (!param) {
                    param = {};
                }

                param['type'] = eventName;
                param['target'] = this;

                this.getLayer()._onGeometryEvent(param);
            }

            this.fire(eventName, param);
        };

        _proto._toJSON = function _toJSON(options) {
            return {
                'feature': this.toGeoJSON(options)
            };
        };

        _proto._exportGraphicOptions = function _exportGraphicOptions(options) {
            var json = {};

            if (isNil(options['options']) || options['options']) {
                json['options'] = this.config();
            }

            if (isNil(options['symbol']) || options['symbol']) {
                json['symbol'] = this.getSymbol();
            }

            if (isNil(options['infoWindow']) || options['infoWindow']) {
                if (this._infoWinOptions) {
                    json['infoWindow'] = this._infoWinOptions;
                }
            }

            return json;
        };

        _proto._exportGeoJSONGeometry = function _exportGeoJSONGeometry() {
            var points = this.getCoordinates();
            var coordinates = Coordinate.toNumberArrays(points);
            return {
                'type': this.getType(),
                'coordinates': coordinates
            };
        };

        _proto._exportProperties = function _exportProperties() {
            var properties = null;
            var geoProperties = this.getProperties();

            if (!isNil(geoProperties)) {
                if (isObject(geoProperties)) {
                    properties = extend({}, geoProperties);
                } else {
                    properties = geoProperties;
                }
            }

            return properties;
        };

        _proto.getAltitude = function getAltitude() {
            var layer = this.getLayer();

            if (!layer) {
                return 0;
            }

            var layerOpts = layer.options,
                properties = this.getProperties();
            var altitude = layerOpts['enableAltitude'] ? properties ? properties[layerOpts['altitudeProperty']] : 0 : 0;
            var layerAltitude = layer.getAltitude ? layer.getAltitude() : 0;

            if (Array.isArray(altitude)) {
                return altitude.map(function(alt) {
                    return alt + layerAltitude;
                });
            }

            return altitude + layerAltitude;
        };

        return Geometry;
    }(JSONAble(Eventable(Handlerable(Class))));

    Geometry.mergeOptions(options);

    var options$1 = {
        'attribution': null,
        'minZoom': null,
        'maxZoom': null,
        'visible': true,
        'opacity': 1,
        'globalCompositeOperation': null,
        'renderer': 'canvas',
        'debugOutline': '#0f0',
        'cssFilter': null,
        'forceRenderOnMoving': false,
        'forceRenderOnZooming': false,
        'forceRenderOnRotating': false,
        'hitDetect': function() {
            return !Browser$1.mobile;
        }()
    };

    var Layer = function(_JSONAble) {
        _inheritsLoose(Layer, _JSONAble);

        function Layer(id, options) {
            var _this;

            var canvas;

            if (options) {
                canvas = options.canvas;
                delete options.canvas;
            }

            _this = _JSONAble.call(this, options) || this;
            _this._canvas = canvas;

            _this.setId(id);

            if (options) {
                _this.setZIndex(options.zIndex);

                if (options.mask) {
                    _this.setMask(Geometry.fromJSON(options.mask));
                }
            }

            return _this;
        }

        var _proto = Layer.prototype;

        _proto.load = function load() {
            if (!this.getMap()) {
                return this;
            }

            if (this.onLoad()) {
                this._initRenderer();

                var zIndex = this.getZIndex();

                if (!isNil(zIndex)) {
                    this._renderer.setZIndex(zIndex);

                    if (!this.isCanvasRender()) {
                        this._renderer.render();
                    }
                }

                this.onLoadEnd();
            }

            return this;
        };

        _proto.getId = function getId() {
            return this._id;
        };

        _proto.setId = function setId(id) {
            var old = this._id;

            if (!isNil(id)) {
                id = id + '';
            }

            this._id = id;
            this.fire('idchange', {
                'old': old,
                'new': id
            });
            return this;
        };

        _proto.addTo = function addTo(map) {
            map.addLayer(this);
            return this;
        };

        _proto.setZIndex = function setZIndex(zIndex) {
            this._zIndex = zIndex;

            if (isNil(zIndex)) {
                delete this.options['zIndex'];
            } else {
                this.options.zIndex = zIndex;
            }

            if (this.map) {
                this.map._sortLayersByZIndex();
            }

            if (this._renderer) {
                this._renderer.setZIndex(zIndex);
            }

            return this;
        };

        _proto.getZIndex = function getZIndex() {
            return this._zIndex || 0;
        };

        _proto.getMinZoom = function getMinZoom() {
            var map = this.getMap();
            var minZoom = this.options['minZoom'];
            return map ? Math.max(map.getMinZoom(), minZoom || 0) : minZoom;
        };

        _proto.getMaxZoom = function getMaxZoom() {
            var map = this.getMap();
            var maxZoom = this.options['maxZoom'];
            return map ? Math.min(map.getMaxZoom(), isNil(maxZoom) ? Infinity : maxZoom) : maxZoom;
        };

        _proto.getOpacity = function getOpacity() {
            return this.options['opacity'];
        };

        _proto.setOpacity = function setOpacity(op) {
            this.config('opacity', op);
            return this;
        };

        _proto.isCanvasRender = function isCanvasRender() {
            var renderer = this._getRenderer();

            return renderer && renderer instanceof CanvasRenderer;
        };

        _proto.getMap = function getMap() {
            if (this.map) {
                return this.map;
            }

            return null;
        };

        _proto.getProjection = function getProjection() {
            var map = this.getMap();
            return map ? map.getProjection() : null;
        };

        _proto.bringToFront = function bringToFront() {
            var layers = this._getLayerList();

            if (!layers.length) {
                return this;
            }

            var topLayer = layers[layers.length - 1];

            if (layers.length === 1 || topLayer === this) {
                return this;
            }

            var max = topLayer.getZIndex();
            this.setZIndex(max + 1);
            return this;
        };

        _proto.bringToBack = function bringToBack() {
            var layers = this._getLayerList();

            if (!layers.length) {
                return this;
            }

            var bottomLayer = layers[0];

            if (layers.length === 1 || bottomLayer === this) {
                return this;
            }

            var min = bottomLayer.getZIndex();
            this.setZIndex(min - 1);
            return this;
        };

        _proto.show = function show() {
            var _this2 = this;

            if (!this.options['visible']) {
                this.options['visible'] = true;
                var renderer = this.getRenderer();

                if (renderer) {
                    renderer.show();
                }

                var map = this.getMap();

                if (renderer && map) {
                    map.once('renderend', function() {
                        _this2.fire('show');
                    });
                } else {
                    this.fire('show');
                }
            }

            return this;
        };

        _proto.hide = function hide() {
            var _this3 = this;

            if (this.options['visible']) {
                this.options['visible'] = false;
                var renderer = this.getRenderer();

                if (renderer) {
                    renderer.hide();
                }

                var map = this.getMap();

                if (renderer && map) {
                    map.once('renderend', function() {
                        _this3.fire('hide');
                    });
                } else {
                    this.fire('hide');
                }
            }

            return this;
        };

        _proto.isVisible = function isVisible() {
            if (isNumber(this.options['opacity']) && this.options['opacity'] <= 0) {
                return false;
            }

            var map = this.getMap();

            if (map) {
                var zoom = map.getZoom();

                if (!isNil(this.options['maxZoom']) && this.options['maxZoom'] < zoom || !isNil(this.options['minZoom']) && this.options['minZoom'] > zoom) {
                    return false;
                }
            }

            if (isNil(this.options['visible'])) {
                this.options['visible'] = true;
            }

            return this.options['visible'];
        };

        _proto.remove = function remove() {
            if (this.map) {
                this.map.removeLayer(this);
            }

            return this;
        };

        _proto.getMask = function getMask() {
            return this._mask;
        };

        _proto.setMask = function setMask(mask) {
            if (!(mask.type === 'Point' && mask._isVectorMarker() || mask.type === 'Polygon' || mask.type === 'MultiPolygon')) {
                throw new Error('Mask for a layer must be a marker with vector marker symbol or a Polygon(MultiPolygon).');
            }

            mask._bindLayer(this);

            if (mask.type === 'Point') {
                mask.updateSymbol({
                    'markerLineColor': 'rgba(0, 0, 0, 0)',
                    'markerFillOpacity': 0
                });
            } else {
                mask.setSymbol({
                    'lineColor': 'rgba(0, 0, 0, 0)',
                    'polygonOpacity': 0
                });
            }

            this._mask = mask;
            this.options.mask = mask.toJSON();

            if (!this.getMap() || this.getMap().isZooming()) {
                return this;
            }

            var renderer = this._getRenderer();

            if (renderer && renderer.setToRedraw) {
                this._getRenderer().setToRedraw();
            }

            return this;
        };

        _proto.removeMask = function removeMask() {
            delete this._mask;
            delete this.options.mask;

            if (!this.getMap() || this.getMap().isZooming()) {
                return this;
            }

            var renderer = this._getRenderer();

            if (renderer && renderer.setToRedraw) {
                this._getRenderer().setToRedraw();
            }

            return this;
        };

        _proto.onLoad = function onLoad() {
            return true;
        };

        _proto.onLoadEnd = function onLoadEnd() {};

        _proto.isLoaded = function isLoaded() {
            return !!this._loaded;
        };

        _proto.getRenderer = function getRenderer() {
            return this._getRenderer();
        };

        _proto.onConfig = function onConfig(conf) {
            if (isNumber(conf['opacity']) || conf['cssFilter']) {
                var renderer = this.getRenderer();

                if (renderer) {
                    renderer.setToRedraw();
                }
            }
        };

        _proto.onAdd = function onAdd() {};

        _proto.onRendererCreate = function onRendererCreate() {};

        _proto.onCanvasCreate = function onCanvasCreate() {};

        _proto.onRemove = function onRemove() {};

        _proto._bindMap = function _bindMap(map, zIndex) {
            if (!map) {
                return;
            }

            this.map = map;

            if (!isNil(zIndex)) {
                this.setZIndex(zIndex);
            }

            this._switchEvents('on', this);

            this.onAdd();
            this.fire('add');
        };

        _proto._initRenderer = function _initRenderer() {
            var renderer = this.options['renderer'];

            if (!this.constructor.getRendererClass) {
                return;
            }

            var clazz = this.constructor.getRendererClass(renderer);

            if (!clazz) {
                throw new Error('Invalid renderer for Layer(' + this.getId() + '):' + renderer);
            }

            this._renderer = new clazz(this);
            this._renderer.layer = this;

            this._renderer.setZIndex(this.getZIndex());

            this._switchEvents('on', this._renderer);

            if (this._renderer.onAdd) {
                this._renderer.onAdd();
            }

            this.onRendererCreate();
            this.fire('renderercreate', {
                'renderer': this._renderer
            });
        };

        _proto._doRemove = function _doRemove() {
            this._loaded = false;
            this.onRemove();

            this._switchEvents('off', this);

            if (this._renderer) {
                this._switchEvents('off', this._renderer);

                this._renderer.remove();

                delete this._renderer;
            }

            delete this.map;
        };

        _proto._switchEvents = function _switchEvents(to, emitter) {
            if (emitter && emitter.getEvents) {
                this.getMap()[to](emitter.getEvents(), emitter);
            }
        };

        _proto._getRenderer = function _getRenderer() {
            return this._renderer;
        };

        _proto._getLayerList = function _getLayerList() {
            if (!this.map) {
                return [];
            }

            return this.map._layers;
        };

        _proto._getMask2DExtent = function _getMask2DExtent() {
            if (!this._mask || !this.getMap()) {
                return null;
            }

            var painter = this._mask._getMaskPainter();

            if (!painter) {
                return null;
            }

            return painter.get2DExtent();
        };

        return Layer;
    }(JSONAble(Eventable(Renderable(Class))));

    Layer.mergeOptions(options$1);
    var fire = Layer.prototype.fire;

    Layer.prototype.fire = function(eventType, param) {
        if (eventType === 'layerload') {
            this._loaded = true;
        }

        if (this.map) {
            if (!param) {
                param = {};
            }

            param['type'] = eventType;
            param['target'] = this;

            this.map._onLayerEvent(param);
        }

        return fire.apply(this, arguments);
    };

    var options$2 = {
        'maxVisualPitch': 70,
        'maxPitch': 80,
        'centerCross': false,
        'zoomInCenter': false,
        'zoomOrigin': null,
        'zoomAnimation': function() {
            return !IS_NODE;
        }(),
        'zoomAnimationDuration': 330,
        'panAnimation': function() {
            return !IS_NODE;
        }(),
        'panAnimationDuration': 600,
        'zoomable': true,
        'enableInfoWindow': true,
        'hitDetect': function() {
            return !Browser$1.mobile;
        }(),
        'hitDetectLimit': 5,
        'fpsOnInteracting': 25,
        'layerCanvasLimitOnInteracting': -1,
        'maxZoom': null,
        'minZoom': null,
        'maxExtent': null,
        'fixCenterOnResize': true,
        'checkSize': true,
        'checkSizeInterval': 1000,
        'renderer': 'canvas',
        'cascadePitches': [10, 60]
    };

    var Map$1 = function(_Handlerable) {
        _inheritsLoose(Map, _Handlerable);

        function Map(container, options) {
            var _this;

            if (!options) {
                throw new Error('Invalid options when creating map.');
            }

            if (!options['center']) {
                throw new Error('Invalid center when creating map.');
            }

            var opts = extend({}, options);
            var zoom = opts['zoom'];
            delete opts['zoom'];
            var center = new Coordinate(opts['center']);
            delete opts['center'];
            var baseLayer = opts['baseLayer'];
            delete opts['baseLayer'];
            var layers = opts['layers'];
            delete opts['layers'];
            _this = _Handlerable.call(this, opts) || this;
            _this.VERSION = Map.VERSION;
            Object.defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), 'id', {
                value: UID(),
                writable: false
            });
            _this._loaded = false;

            _this._initContainer(container);

            _this._panels = {};
            _this._baseLayer = null;
            _this._layers = [];
            _this._zoomLevel = zoom;
            _this._center = center;

            _this.setSpatialReference(opts['spatialReference'] || opts['view']);

            _this.setMaxExtent(opts['maxExtent']);

            _this._mapViewPoint = new Point(0, 0);

            _this._initRenderer();

            _this._updateMapSize(_this._getContainerDomSize());

            if (baseLayer) {
                _this.setBaseLayer(baseLayer);
            }

            if (layers) {
                _this.addLayer(layers);
            }

            _this._Load();

            return _this;
        }

        Map.addOnLoadHook = function addOnLoadHook(fn) {
            var args = Array.prototype.slice.call(arguments, 1);
            var onload = typeof fn === 'function' ? fn : function() {
                this[fn].apply(this, args);
            };
            this.prototype._onLoadHooks = this.prototype._onLoadHooks || [];

            this.prototype._onLoadHooks.push(onload);

            return this;
        };

        var _proto = Map.prototype;

        _proto.isLoaded = function isLoaded() {
            return !!this._loaded;
        };

        _proto.getContainer = function getContainer() {
            return this._containerDOM;
        };

        _proto.getSpatialReference = function getSpatialReference() {
            return this._spatialReference;
        };

        _proto.setSpatialReference = function setSpatialReference(ref) {
            var oldRef = this.options['spatialReference'];

            if (this._loaded && SpatialReference.equals(oldRef, ref)) {
                return this;
            }

            this._updateSpatialReference(ref, oldRef);

            return this;
        };

        _proto._updateSpatialReference = function _updateSpatialReference(ref, oldRef) {
            ref = extend({}, ref);
            this._center = this.getCenter();
            this.options['spatialReference'] = ref;
            this._spatialReference = new SpatialReference(ref);

            if (this.options['spatialReference'] && isFunction(this.options['spatialReference']['projection'])) {
                var projection = this._spatialReference.getProjection();

                this.options['spatialReference']['projection'] = projection['code'];
            }

            this._resetMapStatus();

            this._fireEvent('spatialreferencechange', {
                'old': oldRef,
                'new': extend({}, this.options['spatialReference'])
            });

            return this;
        };

        _proto.onConfig = function onConfig(conf) {
            var ref = conf['spatialReference'] || conf['view'];

            if (!isNil(ref)) {
                this._updateSpatialReference(ref, null);
            }

            return this;
        };

        _proto.getProjection = function getProjection() {
            if (!this._spatialReference) {
                return null;
            }

            return this._spatialReference.getProjection();
        };

        _proto.getFullExtent = function getFullExtent() {
            if (!this._spatialReference) {
                return null;
            }

            return this._spatialReference.getFullExtent();
        };

        _proto.setCursor = function setCursor(cursor) {
            delete this._cursor;

            this._trySetCursor(cursor);

            this._cursor = cursor;
            return this;
        };

        _proto.resetCursor = function resetCursor() {
            return this.setCursor(null);
        };

        _proto.getCenter = function getCenter() {
            if (!this._loaded || !this._prjCenter) {
                return this._center;
            }

            var projection = this.getProjection();
            return projection.unproject(this._prjCenter);
        };

        _proto.setCenter = function setCenter(center) {
            if (!center) {
                return this;
            }

            center = new Coordinate(center);
            var projection = this.getProjection();
            var pcenter = projection.project(center);

            if (!this._verifyExtent(pcenter)) {
                return this;
            }

            if (!this._loaded) {
                this._center = center;
                return this;
            }

            this.onMoveStart();

            this._setPrjCenter(pcenter);

            this.onMoveEnd(this._parseEventFromCoord(this.getCenter()));
            return this;
        };

        _proto.getSize = function getSize() {
            if (isNil(this.width) || isNil(this.height)) {
                return this._getContainerDomSize();
            }

            return new Size(this.width, this.height);
        };

        _proto.getContainerExtent = function getContainerExtent() {
            var visualHeight = this.height;
            var pitch = this.getPitch(),
                maxVisualPitch = this.options['maxVisualPitch'];

            if (maxVisualPitch && pitch > maxVisualPitch) {
                visualHeight = this._getVisualHeight(maxVisualPitch);
            }

            return new PointExtent(0, this.height - visualHeight, this.width, this.height);
        };

        _proto._getVisualHeight = function _getVisualHeight(visualPitch) {
            visualPitch = visualPitch || 1E-2;
            var pitch = (90 - this.getPitch()) * Math.PI / 180;
            var fov = this.getFov() * Math.PI / 180;
            visualPitch *= Math.PI / 180;
            var cameraToCenter = this.cameraCenterDistance / this.getGLScale();
            var tanB = Math.tan(fov / 2);
            var tanP = Math.tan(visualPitch);
            var visualDistance = cameraToCenter * tanB / (1 / tanP - tanB) / Math.sin(visualPitch);
            var x = cameraToCenter * (Math.sin(pitch) * visualDistance / (cameraToCenter + Math.cos(pitch) * visualDistance));
            return this.height / 2 + x;
        };

        _proto.getExtent = function getExtent() {
            return this._pointToExtent(this._get2DExtent());
        };

        _proto.getProjExtent = function getProjExtent() {
            var extent2D = this._get2DExtent();

            return new Extent(this._pointToPrj(extent2D.getMin()), this._pointToPrj(extent2D.getMax()));
        };

        _proto.getPrjExtent = function getPrjExtent() {
            return this.getProjExtent();
        };

        _proto.getMaxExtent = function getMaxExtent() {
            if (!this.options['maxExtent']) {
                return null;
            }

            return new Extent(this.options['maxExtent'], this.getProjection());
        };

        _proto.setMaxExtent = function setMaxExtent(extent) {
            if (extent) {
                var maxExt = new Extent(extent, this.getProjection());
                this.options['maxExtent'] = maxExt;

                if (!this._verifyExtent(this._getPrjCenter())) {
                    this._panTo(this._prjMaxExtent().getCenter());
                }

                var projection = this.getProjection();
                this._prjMaxExtent = maxExt.convertTo(function(c) {
                    return projection.project(c);
                });
            } else {
                delete this.options['maxExtent'];
                delete this._prjMaxExtent;
            }

            return this;
        };

        _proto.getZoom = function getZoom() {
            return this._zoomLevel;
        };

        _proto.getZoomForScale = function getZoomForScale(scale, fromZoom, isFraction) {
            var zoom = this.getZoom();

            if (isNil(fromZoom)) {
                fromZoom = zoom;
            }

            if (scale === 1 && fromZoom === zoom) {
                return zoom;
            }

            var res = this._getResolution(fromZoom),
                targetRes = res / scale;

            var scaleZoom = this.getZoomFromRes(targetRes);

            if (isFraction) {
                return scaleZoom;
            } else {
                var delta = 1E-6;
                return this.getSpatialReference().getZoomDirection() < 0 ? Math.ceil(scaleZoom - delta) : Math.floor(scaleZoom + delta);
            }
        };

        _proto.getZoomFromRes = function getZoomFromRes(res) {
            var resolutions = this._getResolutions(),
                minRes = this._getResolution(this.getMinZoom()),
                maxRes = this._getResolution(this.getMaxZoom());

            if (minRes <= maxRes) {
                if (res <= minRes) {
                    return this.getMinZoom();
                } else if (res >= maxRes) {
                    return this.getMaxZoom();
                }
            } else if (res >= minRes) {
                return this.getMinZoom();
            } else if (res <= maxRes) {
                return this.getMaxZoom();
            }

            var l = resolutions.length;

            for (var i = 0; i < l - 1; i++) {
                if (!resolutions[i]) {
                    continue;
                }

                var gap = resolutions[i + 1] - resolutions[i];
                var test = res - resolutions[i];

                if (sign(gap) === sign(test) && Math.abs(gap) >= Math.abs(test)) {
                    return i + test / gap;
                }
            }

            return l - 1;
        };

        _proto.setZoom = function setZoom(zoom, options) {
            if (options === void 0) {
                options = {
                    'animation': true
                };
            }

            if (isNaN(zoom) || isNil(zoom)) {
                return this;
            }

            zoom = +zoom;

            if (this._loaded && this.options['zoomAnimation'] && options['animation']) {
                this._zoomAnimation(zoom);
            } else {
                this._zoom(zoom);
            }

            return this;
        };

        _proto.getMaxZoom = function getMaxZoom() {
            if (!isNil(this.options['maxZoom'])) {
                return this.options['maxZoom'];
            }

            return this.getMaxNativeZoom();
        };

        _proto.setMaxZoom = function setMaxZoom(maxZoom) {
            var viewMaxZoom = this.getMaxNativeZoom();

            if (maxZoom > viewMaxZoom) {
                maxZoom = viewMaxZoom;
            }

            if (maxZoom !== null && maxZoom < this._zoomLevel) {
                this.setZoom(maxZoom);
                maxZoom = +maxZoom;
            }

            this.options['maxZoom'] = maxZoom;
            return this;
        };

        _proto.getMinZoom = function getMinZoom() {
            if (!isNil(this.options['minZoom'])) {
                return this.options['minZoom'];
            }

            return this._spatialReference.getMinZoom();
        };

        _proto.setMinZoom = function setMinZoom(minZoom) {
            if (minZoom !== null) {
                minZoom = +minZoom;

                var viewMinZoom = this._spatialReference.getMinZoom();

                if (minZoom < viewMinZoom) {
                    minZoom = viewMinZoom;
                }

                if (minZoom > this._zoomLevel) {
                    this.setZoom(minZoom);
                }
            }

            this.options['minZoom'] = minZoom;
            return this;
        };

        _proto.getMaxNativeZoom = function getMaxNativeZoom() {
            var ref = this.getSpatialReference();

            if (!ref) {
                return null;
            }

            return ref.getMaxZoom();
        };

        _proto.getGLZoom = function getGLZoom() {
            return this.getMaxNativeZoom() / 2;
        };

        _proto.getGLScale = function getGLScale(zoom) {
            if (isNil(zoom)) {
                zoom = this.getZoom();
            }

            return this._getResolution(zoom) / this._getResolution(this.getGLZoom());
        };

        _proto.zoomIn = function zoomIn() {
            return this.setZoom(this.getZoom() + 1);
        };

        _proto.zoomOut = function zoomOut() {
            return this.setZoom(this.getZoom() - 1);
        };

        _proto.isZooming = function isZooming() {
            return !!this._zooming;
        };

        _proto.isInteracting = function isInteracting() {
            return this.isZooming() || this.isMoving() || this.isRotating();
        };

        _proto.setCenterAndZoom = function setCenterAndZoom(center, zoom) {
            if (!isNil(zoom) && this._zoomLevel !== zoom) {
                this.setCenter(center);
                this.setZoom(zoom, {
                    animation: false
                });
            } else {
                this.setCenter(center);
            }

            return this;
        };

        _proto.getFitZoom = function getFitZoom(extent, isFraction) {
            var _this2 = this;

            if (!extent || !(extent instanceof Extent)) {
                return this._zoomLevel;
            }

            if (extent['xmin'] === extent['xmax'] && extent['ymin'] === extent['ymax']) {
                return this.getMaxZoom();
            }

            var size = this.getSize();
            var containerExtent = extent.convertTo(function(p) {
                return _this2.coordToContainerPoint(p);
            });
            var w = containerExtent.getWidth(),
                h = containerExtent.getHeight();
            var scaleX = size['width'] / w,
                scaleY = size['height'] / h;
            var scale = this.getSpatialReference().getZoomDirection() < 0 ? Math.max(scaleX, scaleY) : Math.min(scaleX, scaleY);
            var zoom = this.getZoomForScale(scale, null, isFraction);
            return zoom;
        };

        _proto.getView = function getView() {
            return {
                'center': this.getCenter().toArray(),
                'zoom': this.getZoom(),
                'pitch': this.getPitch(),
                'bearing': this.getBearing()
            };
        };

        _proto.setView = function setView(view) {
            if (!view) {
                return this;
            }

            if (view['center']) {
                this.setCenter(view['center']);
            }

            if (view['zoom'] !== null && !isNaN(+view['zoom'])) {
                this.setZoom(+view['zoom'], {
                    'animation': false
                });
            }

            if (view['pitch'] !== null && !isNaN(+view['pitch'])) {
                this.setPitch(+view['pitch']);
            }

            if (view['pitch'] !== null && !isNaN(+view['bearing'])) {
                this.setBearing(+view['bearing']);
            }

            return this;
        };

        _proto.getResolution = function getResolution(zoom) {
            return this._getResolution(zoom);
        };

        _proto.getScale = function getScale(zoom) {
            var z = isNil(zoom) ? this.getZoom() : zoom;

            var max = this._getResolution(this.getMaxNativeZoom()),
                res = this._getResolution(z);

            return res / max;
        };

        _proto.fitExtent = function fitExtent(extent, zoomOffset, options, step) {
            if (options === void 0) {
                options = {};
            }

            if (!extent) {
                return this;
            }

            extent = new Extent(extent, this.getProjection());
            var zoom = this.getFitZoom(extent) + (zoomOffset || 0);
            var center = extent.getCenter();
            if (typeof options['animation'] === 'undefined' || options['animation']) return this._animateTo({
                center: center,
                zoom: zoom
            }, {
                'duration': options['duration'] || this.options['zoomAnimationDuration'],
                'easing': options['easing'] || 'out'
            }, step);
            else return this.setCenterAndZoom(center, zoom);
        };

        _proto.getBaseLayer = function getBaseLayer() {
            return this._baseLayer;
        };

        _proto.setBaseLayer = function setBaseLayer(baseLayer) {
            var isChange = false;

            if (this._baseLayer) {
                isChange = true;

                this._fireEvent('baselayerchangestart');

                this._baseLayer.remove();
            }

            if (!baseLayer) {
                delete this._baseLayer;

                this._fireEvent('baselayerchangeend');

                this._fireEvent('setbaselayer');

                return this;
            }

            this._baseLayer = baseLayer;

            baseLayer._bindMap(this, -1);

            function onbaseLayerload() {
                this._fireEvent('baselayerload');

                if (isChange) {
                    isChange = false;

                    this._fireEvent('baselayerchangeend');
                }
            }

            this._baseLayer.on('layerload', onbaseLayerload, this);

            if (this._loaded) {
                this._baseLayer.load();
            }

            this._fireEvent('setbaselayer');

            return this;
        };

        _proto.removeBaseLayer = function removeBaseLayer() {
            if (this._baseLayer) {
                this._baseLayer.remove();

                delete this._baseLayer;

                this._fireEvent('baselayerremove');
            }

            return this;
        };

        _proto.getLayers = function getLayers(filter) {
            return this._getLayers(function(layer) {
                if (layer === this._baseLayer || layer.getId().indexOf(INTERNAL_LAYER_PREFIX) >= 0) {
                    return false;
                }

                if (filter) {
                    return filter(layer);
                }

                return true;
            });
        };

        _proto.getLayer = function getLayer(id) {
            if (!id) {
                return null;
            }

            var layer = this._layerCache ? this._layerCache[id] : null;

            if (layer) {
                return layer;
            }

            var baseLayer = this.getBaseLayer();

            if (baseLayer && baseLayer.getId() === id) {
                return baseLayer;
            }

            return null;
        };

        _proto.addLayer = function addLayer(layers) {
            if (!layers) {
                return this;
            }

            if (!Array.isArray(layers)) {
                layers = Array.prototype.slice.call(arguments, 0);
                return this.addLayer(layers);
            }

            if (!this._layerCache) {
                this._layerCache = {};
            }

            var mapLayers = this._layers;

            for (var i = 0, len = layers.length; i < len; i++) {
                var layer = layers[i];
                var id = layer.getId();

                if (isNil(id)) {
                    throw new Error('Invalid id for the layer: ' + id);
                }

                if (layer.getMap() === this) {
                    continue;
                }

                if (this._layerCache[id]) {
                    throw new Error('Duplicate layer id in the map: ' + id);
                }

                this._layerCache[id] = layer;

                layer._bindMap(this);

                mapLayers.push(layer);

                if (this._loaded) {
                    layer.load();
                }
            }

            this._sortLayersByZIndex();

            this._fireEvent('addlayer', {
                'layers': layers
            });

            return this;
        };

        _proto.removeLayer = function removeLayer(layers) {
            if (!layers) {
                return this;
            }

            if (!Array.isArray(layers)) {
                return this.removeLayer([layers]);
            }

            var removed = [];

            for (var i = 0, len = layers.length; i < len; i++) {
                var layer = layers[i];

                if (!(layer instanceof Layer)) {
                    layer = this.getLayer(layer);
                }

                if (!layer) {
                    continue;
                }

                var map = layer.getMap();

                if (!map || map !== this) {
                    continue;
                }

                removed.push(layer);

                this._removeLayer(layer, this._layers);

                if (this._loaded) {
                    layer._doRemove();
                }

                var id = layer.getId();

                if (this._layerCache) {
                    delete this._layerCache[id];
                }
            }

            if (removed.length > 0) {
                var renderer = this.getRenderer();

                if (renderer) {
                    renderer.setLayerCanvasUpdated();
                }

                this.once('frameend', function() {
                    removed.forEach(function(layer) {
                        layer.fire('remove');
                    });
                });
            }

            this._fireEvent('removelayer', {
                'layers': layers
            });

            return this;
        };

        _proto.sortLayers = function sortLayers(layers) {
            if (!layers || !Array.isArray(layers)) {
                return this;
            }

            var layersToOrder = [];
            var minZ = Number.MAX_VALUE;

            for (var i = 0, l = layers.length; i < l; i++) {
                var layer = layers[i];

                if (isString(layers[i])) {
                    layer = this.getLayer(layer);
                }

                if (!(layer instanceof Layer) || !layer.getMap() || layer.getMap() !== this) {
                    throw new Error('It must be a layer added to this map to order.');
                }

                if (layer.getZIndex() < minZ) {
                    minZ = layer.getZIndex();
                }

                layersToOrder.push(layer);
            }

            for (var _i = 0, _l = layersToOrder.length; _i < _l; _i++) {
                layersToOrder[_i].setZIndex(minZ + _i);
            }

            return this;
        };

        _proto.toDataURL = function toDataURL(options) {
            if (!options) {
                options = {};
            }

            var mimeType = options['mimeType'];

            if (!mimeType) {
                mimeType = 'image/png';
            }

            var save = options['save'];

            var renderer = this._getRenderer();

            if (renderer && renderer.toDataURL) {
                var file = options['fileName'];

                if (!file) {
                    file = 'export';
                }

                var dataURL = renderer.toDataURL(mimeType);

                if (save && dataURL) {
                    var imgURL;

                    if (typeof Blob !== 'undefined' && typeof atob !== 'undefined') {
                        var blob = b64toBlob(dataURL.replace(/^data:image\/(png|jpeg|jpg);base64,/, ''), mimeType);
                        imgURL = URL.createObjectURL(blob);
                    } else {
                        imgURL = dataURL;
                    }

                    var dlLink = document.createElement('a');
                    dlLink.download = file;
                    dlLink.href = imgURL;
                    document.body.appendChild(dlLink);
                    dlLink.click();
                    document.body.removeChild(dlLink);
                }

                return dataURL;
            }

            return null;
        };

        _proto.coordToPoint = function coordToPoint(coordinate, zoom, out) {
            return this.coordinateToPoint(coordinate, zoom, out);
        };

        _proto.pointToCoord = function pointToCoord(point, zoom, out) {
            return this.pointToCoordinate(point, zoom, out);
        };

        _proto.coordToViewPoint = function coordToViewPoint(coordinate, out, altitude) {
            return this.coordinateToViewPoint(coordinate, out, altitude);
        };

        _proto.viewPointToCoord = function viewPointToCoord(viewPoint, out) {
            return this.viewPointToCoordinate(viewPoint, out);
        };

        _proto.coordToContainerPoint = function coordToContainerPoint(coordinate, zoom, out) {
            return this.coordinateToContainerPoint(coordinate, zoom, out);
        };

        _proto.containerPointToCoord = function containerPointToCoord(containerPoint, out) {
            return this.containerPointToCoordinate(containerPoint, out);
        };

        _proto.containerPointToViewPoint = function containerPointToViewPoint(containerPoint, out) {
            if (out) {
                out.set(containerPoint.x, containerPoint.y);
            } else {
                out = containerPoint.copy();
            }

            return out._sub(this.getViewPoint());
        };

        _proto.viewPointToContainerPoint = function viewPointToContainerPoint(viewPoint, out) {
            if (out) {
                out.set(viewPoint.x, viewPoint.y);
            } else {
                out = viewPoint.copy();
            }

            return out._add(this.getViewPoint());
        };

        _proto.checkSize = function checkSize() {
            var justStart = now() - this._initTime < 1500 && this.width === 0 || this.height === 0;

            var watched = this._getContainerDomSize(),
                oldHeight = this.height,
                oldWidth = this.width;

            if (watched['width'] === oldWidth && watched['height'] === oldHeight) {
                return this;
            }

            var center = this.getCenter();

            if (!this.options['fixCenterOnResize']) {
                var vh = this._getVisualHeight(this.getPitch());

                var nwCP = new Point(0, this.height - vh);

                var nwCoord = this._containerPointToPrj(nwCP);

                this._updateMapSize(watched);

                var vhAfter = this._getVisualHeight(this.getPitch());

                var nwCPAfter = new Point(0, this.height - vhAfter);

                this._setPrjCoordAtContainerPoint(nwCoord, nwCPAfter);

                this._mapViewCoord = this._getPrjCenter();
            } else {
                this._updateMapSize(watched);
            }

            var hided = watched['width'] === 0 || watched['height'] === 0 || oldWidth === 0 || oldHeight === 0;

            if (justStart || hided) {
                this._eventSilence = true;
                this.setCenter(center);
                delete this._eventSilence;
            }

            this._fireEvent('resize');

            return this;
        };

        _proto.locate = function locate(coordinate, dx, dy) {
            return this.getProjection()._locate(new Coordinate(coordinate), dx, dy);
        };

        _proto.getMainPanel = function getMainPanel() {
            return this._getRenderer().getMainPanel();
        };

        _proto.getPanels = function getPanels() {
            return this._panels;
        };

        _proto.remove = function remove() {
            var _this3 = this;

            if (this.isRemoved()) {
                return this;
            }

            this._fireEvent('removestart');

            this._removeDomEvents();

            this._clearHandlers();

            this.removeBaseLayer();
            var layers = this.getLayers();

            for (var i = 0; i < layers.length; i++) {
                layers[i].remove();
            }

            if (this._getRenderer()) {
                this._getRenderer().remove();
            }

            if (this._containerDOM.childNodes && this._containerDOM.childNodes.length > 0) {
                Array.prototype.slice.call(this._containerDOM.childNodes, 0).filter(function(node) {
                    return node.className === 'maptalks-wrapper';
                }).forEach(function(node) {
                    return _this3._containerDOM.removeChild(node);
                });
            }

            delete this._panels;
            delete this._containerDOM;
            delete this.renderer;

            this._fireEvent('removeend');

            this._clearAllListeners();

            return this;
        };

        _proto.isRemoved = function isRemoved() {
            return !this._containerDOM;
        };

        _proto.isMoving = function isMoving() {
            return !!this._moving;
        };

        _proto.onMoveStart = function onMoveStart(param) {
            var prjCenter = this._getPrjCenter();

            if (!this._originCenter || this._verifyExtent(prjCenter)) {
                this._originCenter = prjCenter;
            }

            this._moving = true;

            this._trySetCursor('move');

            this._fireEvent('movestart', this._parseEvent(param ? param['domEvent'] : null, 'movestart'));
        };

        _proto.onMoving = function onMoving(param) {
            this._fireEvent('moving', this._parseEvent(param ? param['domEvent'] : null, 'moving'));
        };

        _proto.onMoveEnd = function onMoveEnd(param) {
            this._moving = false;

            this._trySetCursor('default');

            this._fireEvent('moveend', param && param['domEvent'] ? this._parseEvent(param['domEvent'], 'moveend') : param);

            if (!this._verifyExtent(this._getPrjCenter()) && this._originCenter) {
                var moveTo = this._originCenter;

                this._panTo(moveTo);
            }
        };

        _proto.onDragRotateStart = function onDragRotateStart(param) {
            this._dragRotating = true;

            this._fireEvent('dragrotatestart', this._parseEvent(param ? param['domEvent'] : null, 'dragrotatestart'));
        };

        _proto.onDragRotating = function onDragRotating(param) {
            this._fireEvent('dragrotating', this._parseEvent(param ? param['domEvent'] : null, 'dragrotating'));
        };

        _proto.onDragRotateEnd = function onDragRotateEnd(param) {
            this._dragRotating = false;

            this._fireEvent('dragrotateend', this._parseEvent(param ? param['domEvent'] : null, 'dragrotateend'));
        };

        _proto.isDragRotating = function isDragRotating() {
            return !!this._dragRotating;
        };

        _proto.getRenderer = function getRenderer() {
            return this._getRenderer();
        };

        _proto.getDevicePixelRatio = function getDevicePixelRatio() {
            return this.options['devicePixelRatio'] || Browser$1.devicePixelRatio || 1;
        };

        _proto._initContainer = function _initContainer(container) {
            if (isString(container)) {
                this._containerDOM = document.getElementById(container);

                if (!this._containerDOM) {
                    throw new Error('Invalid container when creating map: \'' + container + '\'');
                }
            } else {
                this._containerDOM = container;

                if (IS_NODE) {
                    this.CanvasClass = this._containerDOM.constructor;
                }
            }

            if (this._containerDOM.childNodes && this._containerDOM.childNodes.length > 0) {
                if (this._containerDOM.childNodes[0].className === 'maptalks-wrapper') {
                    throw new Error('Container is already loaded with another map instance, use map.remove() to clear it.');
                }
            }
        };

        _proto._trySetCursor = function _trySetCursor(cursor) {
            if (!this._cursor && !this._priorityCursor) {
                if (!cursor) {
                    cursor = 'default';
                }

                this._setCursorToPanel(cursor);
            }

            return this;
        };

        _proto._setPriorityCursor = function _setPriorityCursor(cursor) {
            if (!cursor) {
                var hasCursor = false;

                if (this._priorityCursor) {
                    hasCursor = true;
                }

                delete this._priorityCursor;

                if (hasCursor) {
                    this.setCursor(this._cursor);
                }
            } else {
                this._priorityCursor = cursor;

                this._setCursorToPanel(cursor);
            }

            return this;
        };

        _proto._setCursorToPanel = function _setCursorToPanel(cursor) {
            var panel = this.getMainPanel();

            if (panel && panel.style && panel.style.cursor !== cursor) {
                panel.style.cursor = cursor;
            }
        };

        _proto._removeLayer = function _removeLayer(layer, layerList) {
            if (!layer || !layerList) {
                return;
            }

            var index = layerList.indexOf(layer);

            if (index > -1) {
                layerList.splice(index, 1);
            }
        };

        _proto._sortLayersByZIndex = function _sortLayersByZIndex() {
            if (!this._layers) {
                return;
            }

            for (var i = 0, l = this._layers.length; i < l; i++) {
                this._layers[i]._order = i;
            }

            this._layers.sort(function(a, b) {
                var c = a.getZIndex() - b.getZIndex();

                if (c === 0) {
                    return a._order - b._order;
                }

                return c;
            });
        };

        _proto._fireEvent = function _fireEvent(eventName, param) {
            if (this._eventSilence) {
                return;
            }

            this.fire('_' + eventName, param);
            this.fire(eventName, param);
        };

        _proto._Load = function _Load() {
            this._resetMapStatus();

            if (this.options['pitch']) {
                this.setPitch(this.options['pitch']);
                delete this.options['pitch'];
            }

            if (this.options['bearing']) {
                this.setBearing(this.options['bearing']);
                delete this.options['bearing'];
            }

            this._loadAllLayers();

            this._getRenderer().onLoad();

            this._loaded = true;

            this._callOnLoadHooks();

            this._initTime = now();
        };

        _proto._initRenderer = function _initRenderer() {
            var renderer = this.options['renderer'];
            var clazz = Map.getRendererClass(renderer);
            this._renderer = new clazz(this);

            this._renderer.load();
        };

        _proto._getRenderer = function _getRenderer() {
            return this._renderer;
        };

        _proto._loadAllLayers = function _loadAllLayers() {
            function loadLayer(layer) {
                if (layer) {
                    layer.load();
                }
            }

            if (this._baseLayer) {
                this._baseLayer.load();
            }

            this._eachLayer(loadLayer, this.getLayers());
        };

        _proto._getLayers = function _getLayers(filter) {
            var layers = this._baseLayer ? [this._baseLayer].concat(this._layers) : this._layers;
            var result = [];

            for (var i = 0; i < layers.length; i++) {
                if (!filter || filter.call(this, layers[i])) {
                    result.push(layers[i]);
                }
            }

            return result;
        };

        _proto._eachLayer = function _eachLayer(fn) {
            if (arguments.length < 2) {
                return;
            }

            var layerLists = Array.prototype.slice.call(arguments, 1);

            if (layerLists && !Array.isArray(layerLists)) {
                layerLists = [layerLists];
            }

            var layers = [];

            for (var i = 0, len = layerLists.length; i < len; i++) {
                layers = layers.concat(layerLists[i]);
            }

            for (var j = 0, jlen = layers.length; j < jlen; j++) {
                fn.call(fn, layers[j]);
            }
        };

        _proto._onLayerEvent = function _onLayerEvent(param) {
            if (!param) {
                return;
            }

            if (param['type'] === 'idchange') {
                delete this._layerCache[param['old']];
                this._layerCache[param['new']] = param['target'];
            }
        };

        _proto._resetMapStatus = function _resetMapStatus() {
            var maxZoom = this.getMaxZoom(),
                minZoom = this.getMinZoom();

            var viewMaxZoom = this._spatialReference.getMaxZoom(),
                viewMinZoom = this._spatialReference.getMinZoom();

            if (isNil(maxZoom) || maxZoom === -1 || maxZoom > viewMaxZoom) {
                this.setMaxZoom(viewMaxZoom);
            }

            if (isNil(minZoom) || minZoom === -1 || minZoom < viewMinZoom) {
                this.setMinZoom(viewMinZoom);
            }

            maxZoom = this.getMaxZoom();
            minZoom = this.getMinZoom();

            if (maxZoom < minZoom) {
                this.setMaxZoom(minZoom);
            }

            if (isNil(this._zoomLevel) || this._zoomLevel > maxZoom) {
                this._zoomLevel = maxZoom;
            }

            if (this._zoomLevel < minZoom) {
                this._zoomLevel = minZoom;
            }

            delete this._prjCenter;
            var projection = this.getProjection();
            this._prjCenter = projection.project(this._center);

            this._calcMatrices();

            var renderer = this._getRenderer();

            if (renderer) {
                renderer.resetContainer();
            }
        };

        _proto._getContainerDomSize = function _getContainerDomSize() {
            if (!this._containerDOM) {
                return null;
            }

            var containerDOM = this._containerDOM;
            var width, height;

            if (!isNil(containerDOM.width) && !isNil(containerDOM.height)) {
                width = containerDOM.width;
                height = containerDOM.height;
                var dpr = this.getDevicePixelRatio();

                if (dpr !== 1 && containerDOM['layer']) {
                    width /= dpr;
                    height /= dpr;
                }
            } else if (!isNil(containerDOM.clientWidth) && !isNil(containerDOM.clientHeight)) {
                width = parseInt(containerDOM.clientWidth, 0);
                height = parseInt(containerDOM.clientHeight, 0);
            } else {
                throw new Error('can not get size of container');
            }

            return new Size(width, height);
        };

        _proto._updateMapSize = function _updateMapSize(mSize) {
            this.width = mSize['width'];
            this.height = mSize['height'];

            this._getRenderer().updateMapSize(mSize);

            this._calcMatrices();

            return this;
        };

        _proto._getPrjCenter = function _getPrjCenter() {
            return this._prjCenter;
        };

        _proto._setPrjCenter = function _setPrjCenter(pcenter) {
            this._prjCenter = pcenter;

            if (this.isInteracting() && !this.isMoving()) {
                this._mapViewCoord = pcenter;
            }

            this._calcMatrices();
        };

        _proto._setPrjCoordAtContainerPoint = function _setPrjCoordAtContainerPoint(coordinate, point) {
            if (point.x === this.width / 2 && point.y === this.height / 2) {
                return this;
            }

            var t = this._containerPointToPoint(point)._sub(this._prjToPoint(this._getPrjCenter()));

            var pcenter = this._pointToPrj(this._prjToPoint(coordinate).sub(t));

            this._setPrjCenter(pcenter);

            return this;
        };

        _proto._verifyExtent = function _verifyExtent(prjCenter) {
            if (!prjCenter) {
                return false;
            }

            var maxExt = this._prjMaxExtent;

            if (!maxExt) {
                return true;
            }

            return maxExt.contains(prjCenter);
        };

        _proto._offsetCenterByPixel = function _offsetCenterByPixel(pixel) {
            var pos = new Point(this.width / 2 - pixel.x, this.height / 2 - pixel.y);

            var pCenter = this._containerPointToPrj(pos);

            this._setPrjCenter(pCenter);

            return pCenter;
        };

        _proto.offsetPlatform = function offsetPlatform(offset) {
            if (!offset) {
                return this._mapViewPoint;
            } else {
                this._getRenderer().offsetPlatform(offset);

                this._mapViewCoord = this._getPrjCenter();
                this._mapViewPoint = this._mapViewPoint.add(offset);
                return this;
            }
        };

        _proto.getViewPoint = function getViewPoint() {
            var offset = this._getViewPointFrameOffset();

            var panelOffset = this.offsetPlatform();

            if (offset) {
                panelOffset = panelOffset.add(offset);
            }

            return panelOffset;
        };

        _proto._resetMapViewPoint = function _resetMapViewPoint() {
            this._mapViewPoint = new Point(0, 0);
            this._mapViewCoord = this._getPrjCenter();
        };

        _proto._getResolution = function _getResolution(zoom) {
            if ((zoom === undefined || zoom === this._zoomLevel) && this._mapRes !== undefined) {
                return this._mapRes;
            } else if (zoom === this.getGLZoom() && this._mapGlRes !== undefined) {
                return this._mapGlRes;
            }

            if (isNil(zoom)) {
                zoom = this._zoomLevel;
            }

            return this._spatialReference.getResolution(zoom);
        };

        _proto._getResolutions = function _getResolutions() {
            return this._spatialReference.getResolutions();
        };

        _proto._prjToPoint = function _prjToPoint(pCoord, zoom, out) {
            zoom = isNil(zoom) ? this.getZoom() : zoom;
            return this._spatialReference.getTransformation().transform(pCoord, this._getResolution(zoom), out);
        };

        _proto._pointToPrj = function _pointToPrj(point, zoom, out) {
            zoom = isNil(zoom) ? this.getZoom() : zoom;
            return this._spatialReference.getTransformation().untransform(point, this._getResolution(zoom), out);
        };

        _proto._pointToPoint = function _pointToPoint(point, zoom, out) {
            if (out) {
                out.x = point.x;
                out.y = point.y;
            } else {
                out = point.copy();
            }

            if (!isNil(zoom)) {
                return out._multi(this._getResolution(zoom) / this._getResolution());
            }

            return out;
        };

        _proto._pointToPointAtZoom = function _pointToPointAtZoom(point, zoom, out) {
            if (out) {
                out.x = point.x;
                out.y = point.y;
            } else {
                out = point.copy();
            }

            if (!isNil(zoom)) {
                return out._multi(this._getResolution() / this._getResolution(zoom));
            }

            return out;
        };

        _proto._containerPointToPrj = function _containerPointToPrj(containerPoint, out) {
            return this._pointToPrj(this._containerPointToPoint(containerPoint, undefined, out), undefined, out);
        };

        _proto._callOnLoadHooks = function _callOnLoadHooks() {
            var proto = Map.prototype;

            if (!proto._onLoadHooks) {
                return;
            }

            for (var i = 0, l = proto._onLoadHooks.length; i < l; i++) {
                proto._onLoadHooks[i].call(this);
            }
        };

        return Map;
    }(Handlerable(Eventable(Renderable(Class))));

    Map$1.include({
        coordinateToPoint: function() {
            var COORD = new Coordinate(0, 0);
            return function(coordinate, zoom, out) {
                var prjCoord = this.getProjection().project(coordinate, COORD);
                return this._prjToPoint(prjCoord, zoom, out);
            };
        }(),
        pointToCoordinate: function() {
            var COORD = new Coordinate(0, 0);
            return function(point, zoom, out) {
                var prjCoord = this._pointToPrj(point, zoom, COORD);

                return this.getProjection().unproject(prjCoord, out);
            };
        }(),
        coordinateToViewPoint: function() {
            var COORD = new Coordinate(0, 0);
            return function(coordinate, out, altitude) {
                return this._prjToViewPoint(this.getProjection().project(coordinate, COORD), out, altitude);
            };
        }(),
        viewPointToCoordinate: function() {
            var COORD = new Coordinate(0, 0);
            return function(viewPoint, out) {
                return this.getProjection().unproject(this._viewPointToPrj(viewPoint, COORD), out);
            };
        }(),
        coordinateToContainerPoint: function() {
            var COORD = new Coordinate(0, 0);
            return function(coordinate, zoom, out) {
                var pCoordinate = this.getProjection().project(coordinate, COORD);
                return this._prjToContainerPoint(pCoordinate, zoom, out);
            };
        }(),
        containerPointToCoordinate: function() {
            var COORD = new Coordinate(0, 0);
            return function(containerPoint, out) {
                var pCoordinate = this._containerPointToPrj(containerPoint, COORD);

                return this.getProjection().unproject(pCoordinate, out);
            };
        }(),
        containerToExtent: function() {
            var POINT0 = new Point(0, 0);
            var POINT1 = new Point(0, 0);
            return function(containerExtent) {
                var extent2D = new PointExtent(this._containerPointToPoint(containerExtent.getMin(POINT0), undefined, POINT0), this._containerPointToPoint(containerExtent.getMax(POINT1), undefined, POINT1));
                return this._pointToExtent(extent2D);
            };
        }(),
        distanceToPixel: function() {
            var POINT0 = new Point(0, 0);
            var POINT1 = new Point(0, 0);
            return function(xDist, yDist, zoom) {
                var projection = this.getProjection();

                if (!projection) {
                    return null;
                }

                var scale = this.getScale() / this.getScale(zoom);
                var center = this.getCenter(),
                    target = projection.locate(center, xDist, yDist);
                var p0 = this.coordToContainerPoint(center, undefined, POINT0),
                    p1 = this.coordToContainerPoint(target, undefined, POINT1);

                p1._sub(p0)._multi(scale)._abs();

                return new Size(p1.x, p1.y);
            };
        }(),
        distanceToPoint: function() {
            var POINT = new Point(0, 0);
            return function(xDist, yDist, zoom, paramCenter) {
                var projection = this.getProjection();

                if (!projection) {
                    return null;
                }

                var center = paramCenter || this.getCenter(),
                    target = projection.locate(center, xDist, yDist);
                var p0 = this.coordToPoint(center, zoom, POINT),
                    p1 = this.coordToPoint(target, zoom);

                p1._sub(p0)._abs();

                return p1;
            };
        }(),
        pixelToDistance: function() {
            var COORD0 = new Coordinate(0, 0);
            var COORD1 = new Coordinate(0, 0);
            return function(width, height) {
                var projection = this.getProjection();

                if (!projection) {
                    return null;
                }

                var fullExt = this.getFullExtent();
                var d = fullExt['top'] > fullExt['bottom'] ? -1 : 1;
                var target = COORD0.set(this.width / 2 + width, this.height / 2 + d * height);
                var coord = this.containerPointToCoord(target, COORD1);
                return projection.measureLength(this.getCenter(), coord);
            };
        }(),
        pointToDistance: function() {
            var POINT = new Point(0, 0);
            var COORD = new Coordinate(0, 0);
            return function(dx, dy, zoom) {
                var projection = this.getProjection();

                if (!projection) {
                    return null;
                }

                var c = this._prjToPoint(this._getPrjCenter(), zoom, POINT);

                c._add(dx, dy);

                var target = this.pointToCoord(c, zoom, COORD);
                return projection.measureLength(this.getCenter(), target);
            };
        }(),
        locateByPoint: function() {
            var POINT = new Point(0, 0);
            return function(coordinate, px, py) {
                var point = this.coordToContainerPoint(coordinate, undefined, POINT);
                return this.containerPointToCoord(point._add(px, py));
            };
        }(),
        _get2DExtent: function() {
            var POINT = new Point(0, 0);
            return function(zoom, out) {
                var _this4 = this;

                var cached;

                if ((zoom === undefined || zoom === this._zoomLevel) && this._mapExtent2D) {
                    cached = this._mapExtent2D;
                } else if (zoom === this.getGLZoom() && this._mapGlExtent2D) {
                    cached = this._mapGlExtent2D;
                }

                if (cached) {
                    if (out) {
                        out.set(cached['xmin'], cached['ymin'], cached['xmax'], cached['ymax']);
                        return out;
                    }

                    return cached.copy();
                }

                var cExtent = this.getContainerExtent();
                return cExtent.convertTo(function(c) {
                    return _this4._containerPointToPoint(c, zoom, POINT);
                }, out);
            };
        }(),
        _pointToExtent: function() {
            var COORD0 = new Coordinate(0, 0);
            var COORD1 = new Coordinate(0, 0);
            return function(extent2D) {
                var min2d = extent2D.getMin(),
                    max2d = extent2D.getMax();
                var fullExtent = this.getFullExtent();

                var _ref = !fullExtent || fullExtent.left <= fullExtent.right ? [min2d.x, max2d.x] : [max2d.x, min2d.x],
                    minx = _ref[0],
                    maxx = _ref[1];

                var _ref2 = !fullExtent || fullExtent.top > fullExtent.bottom ? [max2d.y, min2d.y] : [min2d.y, max2d.y],
                    miny = _ref2[0],
                    maxy = _ref2[1];

                var min = min2d.set(minx, maxy);
                var max = max2d.set(maxx, miny);
                return new Extent(this.pointToCoord(min, undefined, COORD0), this.pointToCoord(max, undefined, COORD1), this.getProjection());
            };
        }(),
        _getViewPointFrameOffset: function() {
            var POINT = new Point(0, 0);
            return function() {
                if (this.isZooming()) {
                    return null;
                }

                var pcenter = this._getPrjCenter();

                if (this._mapViewCoord && !this._mapViewCoord.equals(pcenter)) {
                    return this._prjToContainerPoint(this._mapViewCoord)._sub(this._prjToContainerPoint(pcenter, undefined, POINT));
                }

                return null;
            };
        }(),
        _viewPointToPrj: function() {
            var POINT = new Point(0, 0);
            return function(viewPoint, out) {
                return this._containerPointToPrj(this.viewPointToContainerPoint(viewPoint, POINT), out);
            };
        }(),
        _prjToContainerPoint: function() {
            var POINT = new Point(0, 0);
            return function(pCoordinate, zoom, out, altitude) {
                return this._pointToContainerPoint(this._prjToPoint(pCoordinate, zoom, POINT), zoom, altitude || 0, out);
            };
        }(),
        _prjToViewPoint: function() {
            var POINT = new Point(0, 0);
            return function(pCoordinate, out, altitude) {
                var containerPoint = this._prjToContainerPoint(pCoordinate, undefined, POINT, altitude);

                return this.containerPointToViewPoint(containerPoint, out);
            };
        }(),
        _viewPointToPoint: function() {
            var POINT = new Point(0, 0);
            return function(viewPoint, zoom, out) {
                return this._containerPointToPoint(this.viewPointToContainerPoint(viewPoint, POINT), zoom, out);
            };
        }(),
        _pointToViewPoint: function() {
            var COORD = new Coordinate(0, 0);
            return function(point, zoom, out) {
                return this._prjToViewPoint(this._pointToPrj(point, zoom, COORD), out);
            };
        }()
    });
    Map$1.mergeOptions(options$2);

    var MapDoubleClickZoomHandler = function(_Handler) {
        _inheritsLoose(MapDoubleClickZoomHandler, _Handler);

        function MapDoubleClickZoomHandler() {
            return _Handler.apply(this, arguments) || this;
        }

        var _proto = MapDoubleClickZoomHandler.prototype;

        _proto.addHooks = function addHooks() {
            if (!this.target) {
                return;
            }

            this.target.on('_dblclick', this._onDoubleClick, this);
        };

        _proto.removeHooks = function removeHooks() {
            if (!this.target) {
                return;
            }

            this.target.off('_dblclick', this._onDoubleClick, this);
        };

        _proto._onDoubleClick = function _onDoubleClick(param) {
            var map = this.target;

            if (map.options['doubleClickZoom']) {
                var oldZoom = map.getZoom(),
                    zoom = param['domEvent']['shiftKey'] ? Math.ceil(oldZoom) - 1 : Math.floor(oldZoom) + 1;

                map._zoomAnimation(zoom, param['containerPoint']);
            }
        };

        return MapDoubleClickZoomHandler;
    }(Handler$1);

    Map$1.mergeOptions({
        'doubleClickZoom': true
    });
    Map$1.addOnLoadHook('addHandler', 'doubleClickZoom', MapDoubleClickZoomHandler);

    var MapDragHandler = function(_Handler) {
        _inheritsLoose(MapDragHandler, _Handler);

        function MapDragHandler() {
            return _Handler.apply(this, arguments) || this;
        }

        var _proto = MapDragHandler.prototype;

        _proto.addHooks = function addHooks() {
            var map = this.target;

            if (!map) {
                return;
            }

            var dom = map._panels.mapWrapper || map._containerDOM;
            this._dragHandler = new DragHandler(dom, {
                'cancelOn': this._cancelOn.bind(this),
                'rightclick': true
            });

            this._dragHandler.on('mousedown', this._onMouseDown, this).on('dragstart', this._onDragStart, this).on('dragging', this._onDragging, this).on('dragend', this._onDragEnd, this).enable();
        };

        _proto.removeHooks = function removeHooks() {
            this._dragHandler.off('mousedown', this._onMouseDown, this).off('dragstart', this._onDragStart, this).off('dragging', this._onDragging, this).off('dragend', this._onDragEnd, this);

            this._dragHandler.remove();

            delete this._dragHandler;
        };

        _proto._cancelOn = function _cancelOn(domEvent) {
            if (this.target.isZooming() || this._ignore(domEvent)) {
                return true;
            }

            return false;
        };

        _proto._ignore = function _ignore(param) {
            if (!param) {
                return false;
            }

            if (param.domEvent) {
                param = param.domEvent;
            }

            return this.target._ignoreEvent(param);
        };

        _proto._onMouseDown = function _onMouseDown(param) {
            delete this.startDragTime;
            delete this._mode;

            if (param.domEvent.button === 2 || param.domEvent.ctrlKey) {
                if (this.target.options['dragRotate'] || this.target.options['dragPitch']) {
                    this._mode = 'rotatePitch';
                }
            } else if (this.target.options['dragPan']) {
                this._mode = 'move';
            }

            this.target._stopAnim(this.target._mapAnimPlayer);

            preventDefault(param['domEvent']);
        };

        _proto._onDragStart = function _onDragStart(param) {
            this.startDragTime = now();

            if (this._mode === 'move') {
                this._moveStart(param);
            } else if (this._mode === 'rotatePitch') {
                this._rotateStart(param);
            }
        };

        _proto._onDragging = function _onDragging(param) {
            var map = this.target;

            if (map._isEventOutMap(param['domEvent'])) {
                return;
            }

            if (this._mode === 'move') {
                this._moving(param);
            } else if (this._mode === 'rotatePitch') {
                this._rotating(param);
            }
        };

        _proto._onDragEnd = function _onDragEnd(param) {
            if (this._mode === 'move') {
                this._moveEnd(param);
            } else if (this._mode === 'rotatePitch') {
                this._rotateEnd(param);
            }

            delete this.startDragTime;
            delete this.startBearing;
        };

        _proto._start = function _start(param) {
            this.preX = param['mousePos'].x;
            this.preY = param['mousePos'].y;
            this.startX = this.preX;
            this.startY = this.preY;
        };

        _proto._moveStart = function _moveStart(param) {
            this._start(param);

            var map = this.target;
            map.onMoveStart(param);
            var p = getEventContainerPoint(map._getActualEvent(param.domEvent), map.getContainer());
            this.startPrjCoord = map._containerPointToPrj(p);
        };

        _proto._moving = function _moving(param) {
            if (!this.startDragTime) {
                return;
            }

            var map = this.target;
            var p = getEventContainerPoint(map._getActualEvent(param.domEvent), map.getContainer());

            map._setPrjCoordAtContainerPoint(this.startPrjCoord, p);

            map.onMoving(param);
        };

        _proto._moveEnd = function _moveEnd(param) {
            if (!this.startDragTime) {
                return;
            }

            var map = this.target;
            var t = now() - this.startDragTime;
            var mx = param['mousePos'].x,
                my = param['mousePos'].y;
            var dx = mx - this.startX;
            var dy = my - this.startY;

            this._clear();

            if (map.options['panAnimation'] && !param.interupted && map._verifyExtent(map._getPrjCenter()) && t < 280 && Math.abs(dy) + Math.abs(dx) > 5) {
                t = 5 * t * (Math.abs(dx) + Math.abs(dy)) / 500;
                map.panBy(new Point(dx, dy), {
                    'duration': t
                });
            } else {
                map.onMoveEnd(param);
            }
        };

        _proto._rotateStart = function _rotateStart(param) {
            this._start(param);

            delete this._rotateMode;
            this.startBearing = this.target.getBearing();
            this.target.onDragRotateStart(param);
            this._db = 0;
        };

        _proto._rotating = function _rotating(param) {
            var map = this.target;
            var mx = param['mousePos'].x,
                my = param['mousePos'].y;
            var prePitch = map.getPitch(),
                preBearing = map.getBearing();
            var dx = Math.abs(mx - this.preX),
                dy = Math.abs(my - this.preY);

            if (!this._rotateMode) {
                if (map.options['dragRotatePitch']) {
                    this._rotateMode = 'rotate_pitch';
                } else if (dx > dy) {
                    this._rotateMode = 'rotate';
                } else if (dx < dy) {
                    this._rotateMode = 'pitch';
                } else {
                    this._rotateMode = 'rotate';
                }
            }

            if (this._rotateMode === 'pitch' && prePitch === 0 && dy < 10) {
                return;
            }

            if (this._rotateMode.indexOf('rotate') >= 0 && map.options['dragRotate']) {
                var db = 0;

                if (map.options['dragPitch'] || dx > dy) {
                    db = -0.6 * (this.preX - mx);
                } else if (mx > map.width / 2) {
                    db = 0.6 * (this.preY - my);
                } else {
                    db = -0.6 * (this.preY - my);
                }

                var bearing = map.getBearing() + db;
                this._db = this._db || 0;
                this._db += db;
                map.setBearing(bearing);
            }

            if (this._rotateMode.indexOf('pitch') >= 0 && map.options['dragPitch']) {
                map.setPitch(map.getPitch() + (this.preY - my) * 0.4);
            }

            this.preX = mx;
            this.preY = my;

            if (map.getBearing() !== preBearing || map.getPitch() !== prePitch) {
                map.onDragRotating(param);
            }
        };

        _proto._rotateEnd = function _rotateEnd(param) {
            var map = this.target;
            var bearing = map.getBearing();

            this._clear();

            var t = now() - this.startDragTime;
            map.onDragRotateEnd(param);

            if (Math.abs(bearing - this.startBearing) > 20 && (this._rotateMode === 'rotate' || this._rotateMode === 'rotate_pitch') && !param.interupted && t < 400) {
                var _bearing = map.getBearing();

                map._animateTo({
                    'bearing': _bearing + this._db / 2
                }, {
                    'easing': 'out',
                    'duration': 800
                });
            }
        };

        _proto._clear = function _clear() {
            delete this.startPrjCoord;
            delete this.preX;
            delete this.preY;
            delete this.startX;
            delete this.startY;
        };

        return MapDragHandler;
    }(Handler$1);

    Map$1.mergeOptions({
        'draggable': true,
        'dragPan': true,
        'dragRotatePitch': true,
        'dragRotate': true,
        'dragPitch': true
    });
    Map$1.addOnLoadHook('addHandler', 'draggable', MapDragHandler);

    var EVENTS = 'mousedown ' + 'mouseup ' + 'mousemove ' + 'click ' + 'dblclick ' + 'contextmenu ' + 'touchstart ' + 'touchmove ' + 'touchend';

    var MapGeometryEventsHandler = function(_Handler) {
        _inheritsLoose(MapGeometryEventsHandler, _Handler);

        function MapGeometryEventsHandler() {
            return _Handler.apply(this, arguments) || this;
        }

        var _proto = MapGeometryEventsHandler.prototype;

        _proto.addHooks = function addHooks() {
            var map = this.target;
            var dom = map._panels.allLayers || map._containerDOM;
            on(dom, EVENTS, this._identifyGeometryEvents, this);
        };

        _proto.removeHooks = function removeHooks() {
            var map = this.target;
            var dom = map._panels.allLayers || map._containerDOM;
            off(dom, EVENTS, this._identifyGeometryEvents, this);
        };

        _proto._identifyGeometryEvents = function _identifyGeometryEvents(domEvent, type) {
            var map = this.target;

            if (map.isInteracting() || map._ignoreEvent(domEvent)) {
                return;
            }

            var layers = map._getLayers(function(layer) {
                if (layer.identify && layer.options['geometryEvents']) {
                    return true;
                }

                return false;
            });

            if (!layers.length) {
                return;
            }

            var oneMoreEvent = null;
            var eventType = type || domEvent.type;

            if (eventType === 'mousedown' || eventType === 'touchstart' && domEvent.touches.length === 1) {
                this._mouseDownTime = now();
            } else if ((eventType === 'click' || eventType === 'touchend') && this._mouseDownTime) {
                var downTime = this._mouseDownTime;
                delete this._mouseDownTime;
                var time = now();

                if (time - downTime > 300) {
                    if (eventType === 'click') {
                        return;
                    }
                } else if (eventType === 'touchend') {
                    oneMoreEvent = 'click';
                }
            }

            var actual = domEvent.touches && domEvent.touches.length > 0 ? domEvent.touches[0] : domEvent.changedTouches && domEvent.changedTouches.length > 0 ? domEvent.changedTouches[0] : domEvent;

            if (!actual) {
                return;
            }

            var containerPoint = getEventContainerPoint(actual, map._containerDOM),
                coordinate = map.containerPointToCoordinate(containerPoint);

            if (eventType === 'touchstart') {
                preventDefault(domEvent);
            }

            var geometryCursorStyle = null;
            var identifyOptions = {
                'includeInternals': true,
                'filter': function filter(geometry) {
                    if (!(geometry instanceof Geometry)) {
                        return false;
                    }

                    var eventToFire = geometry._getEventTypeToFire(domEvent);

                    if (eventType === 'mousemove') {
                        if (!geometryCursorStyle && geometry.options['cursor']) {
                            geometryCursorStyle = geometry.options['cursor'];
                        }

                        if (!geometry.listens('mousemove') && !geometry.listens('mouseover') && !geometry.listens('mouseenter')) {
                            return false;
                        }
                    } else if (!geometry.listens(eventToFire) && !geometry.listens(oneMoreEvent)) {
                        return false;
                    }

                    return true;
                },
                'count': 1,
                'coordinate': coordinate,
                'onlyVisible': map.options['onlyVisibleGeometryEvents'],
                'layers': layers
            };
            var callback = fireGeometryEvent.bind(this);

            if (eventType === 'mousemove' || eventType === 'touchmove') {
                this._queryIdentifyTimeout = map.getRenderer().callInNextFrame(function() {
                    if (map.isInteracting()) {
                        return;
                    }

                    map.identify(identifyOptions, callback);
                });
            } else {
                map.identify(identifyOptions, callback);
            }

            function fireGeometryEvent(geometries) {
                var propagation = true;

                if (eventType === 'mousemove') {
                    var geoMap = {};

                    if (geometries.length > 0) {
                        for (var i = geometries.length - 1; i >= 0; i--) {
                            var geo = geometries[i];

                            if (!(geo instanceof Geometry)) {
                                continue;
                            }

                            var iid = geo._getInternalId();

                            geoMap[iid] = geo;

                            geo._onEvent(domEvent);

                            if (!this._prevOverGeos || !this._prevOverGeos.geomap[iid]) {
                                geo._onEvent(domEvent, 'mouseenter');
                            }

                            propagation = geo._onEvent(domEvent, 'mouseover');
                        }
                    }

                    map._setPriorityCursor(geometryCursorStyle);

                    var oldTargets = this._prevOverGeos && this._prevOverGeos.geos;
                    this._prevOverGeos = {
                        'geos': geometries,
                        'geomap': geoMap
                    };

                    if (oldTargets && oldTargets.length > 0) {
                        for (var _i = oldTargets.length - 1; _i >= 0; _i--) {
                            var oldTarget = oldTargets[_i];

                            if (!(oldTarget instanceof Geometry)) {
                                continue;
                            }

                            var oldTargetId = oldTargets[_i]._getInternalId();

                            if (!geoMap[oldTargetId]) {
                                propagation = oldTarget._onEvent(domEvent, 'mouseout');
                            }
                        }
                    }
                } else {
                    if (!geometries || !geometries.length) {
                        return;
                    }

                    for (var _i2 = geometries.length - 1; _i2 >= 0; _i2--) {
                        if (!(geometries[_i2] instanceof Geometry)) {
                            continue;
                        }

                        propagation = geometries[_i2]._onEvent(domEvent);

                        if (oneMoreEvent) {
                            geometries[_i2]._onEvent(domEvent, oneMoreEvent);
                        }

                        break;
                    }
                }

                if (propagation === false) {
                    stopPropagation(domEvent);
                }
            }
        };

        return MapGeometryEventsHandler;
    }(Handler$1);

    Map$1.mergeOptions({
        'geometryEvents': true,
        'onlyVisibleGeometryEvents': true
    });
    Map$1.addOnLoadHook('addHandler', 'geometryEvents', MapGeometryEventsHandler);

    var wheelZoomDelta = 4.000244140625;
    var defaultZoomRate = 1 / 100;
    var wheelZoomRate = 1 / 450;
    var maxScalePerFrame = 2;

    var MapScrollWheelZoomHandler = function(_Handler) {
        _inheritsLoose(MapScrollWheelZoomHandler, _Handler);

        function MapScrollWheelZoomHandler(target) {
            var _this;

            _this = _Handler.call(this, target) || this;
            _this._thisScrollZoom = _this._scrollZoom.bind(_assertThisInitialized(_assertThisInitialized(_this)));
            _this._wheelZoomRate = wheelZoomRate;
            _this._defaultZoomRate = defaultZoomRate;
            _this._delta = 0;
            return _this;
        }

        var _proto = MapScrollWheelZoomHandler.prototype;

        _proto.addHooks = function addHooks() {
            addDomEvent(this.target._containerDOM, 'wheel', this._onWheelScroll, this);
        };

        _proto.removeHooks = function removeHooks() {
            removeDomEvent(this.target._containerDOM, 'wheel', this._onWheelScroll);
        };

        _proto._onWheelScroll = function _onWheelScroll(evt) {
            preventDefault(evt);
            stopPropagation(evt);
            var map = this.target;

            if (map._ignoreEvent(evt) || !map.options['zoomable']) {
                return false;
            }

            var container = map._containerDOM;

            var origin = map._checkZoomOrigin(getEventContainerPoint(evt, container));

            if (map.options['seamlessZoom']) {
                if (!this._zooming) {
                    this._trackPadSuspect = 0;
                    this._ensureTrackpad = false;
                }

                return this._seamless(evt, origin);
            } else {
                return this._interval(evt, origin);
            }
        };

        _proto._seamless = function _seamless(evt, origin) {
            var value = evt.deltaMode === window.WheelEvent.DOM_DELTA_LINE ? evt.deltaY * 60 : evt.deltaY;

            if (value % wheelZoomDelta !== 0) {
                if (!this._ensureTrackpad) {
                    if (Math.abs(value) < 60) {
                        this._trackPadSuspect++;
                    } else {
                        this._trackPadSuspect = 0;
                    }

                    if (this._trackPadSuspect >= 2) {
                        this._ensureTrackpad = true;
                    }
                }

                if (this._ensureTrackpad) {
                    value *= 14;
                }
            }

            if (evt.shiftKey && value) value = value / 4;
            this._lastWheelEvent = evt;
            this._delta -= value;

            if (!this._zooming && this._delta) {
                var map = this.target;
                this._zoomOrigin = origin;
                map.onZoomStart(null, origin);
            }

            this._start();
        };

        _proto._start = function _start() {
            if (!this._delta) return;
            this._zooming = true;
            var map = this.target;

            if (!this._active) {
                map.getRenderer().callInNextFrame(this._thisScrollZoom);
                this._active = true;
            }
        };

        _proto._scrollZoom = function _scrollZoom() {
            var _this2 = this;

            this._active = false;

            if (!this._delta) {
                return;
            }

            var zoomRate = Math.abs(this._delta) > wheelZoomDelta ? this._wheelZoomRate : this._defaultZoomRate;
            var scale = maxScalePerFrame / (1 + Math.exp(-Math.abs(this._delta * zoomRate)));

            if (this._delta < 0 && scale !== 0) {
                scale = 1 / scale;
            }

            var map = this.target;
            var zoom = map.getZoom();
            var targetZoom = map.getZoomForScale(scale, zoom, true);
            this._delta = 0;
            map.onZooming(targetZoom, this._zoomOrigin);

            if (this._timeout) {
                clearTimeout(this._timeout);
            }

            this._timeout = setTimeout(function() {
                _this2._zooming = false;
                delete _this2._timeout;
                map.onZoomEnd(map.getZoom(), _this2._zoomOrigin);
            }, 210);
        };

        _proto._interval = function _interval(evt, origin) {
            var _this3 = this;

            var map = this.target;

            if (this._zooming) {
                this._requesting++;
                return false;
            }

            this._requesting = 0;
            var levelValue = (evt.deltaY ? evt.deltaY * -1 : evt.wheelDelta ? evt.wheelDelta : evt.detail) > 0 ? 1 : -1;

            if (evt.detail) {
                levelValue *= -1;
            }

            var zoom = map.getZoom();
            var nextZoom = zoom + levelValue;
            nextZoom = map._checkZoom(levelValue > 0 ? Math.ceil(nextZoom) : Math.floor(nextZoom));

            if (nextZoom === zoom) {
                return false;
            }

            this._zooming = true;

            if (!this._delta) {
                map.onZoomStart(null, origin);
                this._origin = origin;
                this._delta = levelValue;
                this._startZoom = map.getZoom();
            }

            var duration = 90;

            map._animateTo({
                'zoom': nextZoom - this._delta * 1 / 2,
                'around': this._origin
            }, {
                'continueOnViewChanged': true,
                'easing': 'linear',
                'duration': duration,
                'wheelZoom': true
            }, function(frame) {
                if (frame.state.playState !== 'finished') {
                    if (frame.state.playState !== 'running') {
                        delete _this3._zooming;
                        delete _this3._requesting;
                    }

                    return;
                }

                if (_this3._requesting < 1 || Math.abs(nextZoom - _this3._startZoom) > 2 || nextZoom === map.getMaxZoom() || nextZoom === map.getMinZoom()) {
                    map._animateTo({
                        'zoom': nextZoom,
                        'around': _this3._origin
                    }, {
                        'continueOnViewChanged': true,
                        'duration': 100
                    }, function(frame) {
                        if (frame.state.playState !== 'running') {
                            delete _this3._zooming;
                            delete _this3._requesting;
                        }
                    });

                    delete _this3._startZoom;
                    delete _this3._origin;
                    delete _this3._delta;
                    _this3._requesting = 0;
                } else if (!isNil(_this3._requesting)) {
                    delete _this3._zooming;

                    _this3._onWheelScroll(evt);
                }
            });

            return false;
        };

        return MapScrollWheelZoomHandler;
    }(Handler$1);

    Map$1.mergeOptions({
        'scrollWheelZoom': true,
        'seamlessZoom': false
    });
    Map$1.addOnLoadHook('addHandler', 'scrollWheelZoom', MapScrollWheelZoomHandler);

    var MapTouchZoomHandler = function(_Handler) {
        _inheritsLoose(MapTouchZoomHandler, _Handler);

        function MapTouchZoomHandler() {
            return _Handler.apply(this, arguments) || this;
        }

        var _proto = MapTouchZoomHandler.prototype;

        _proto.addHooks = function addHooks() {
            addDomEvent(this.target.getContainer(), 'touchstart', this._onTouchStart, this);
        };

        _proto.removeHooks = function removeHooks() {
            removeDomEvent(this.target.getContainer(), 'touchstart', this._onTouchStart);
        };

        _proto._onTouchStart = function _onTouchStart(event) {
            var map = this.target;

            if (!event.touches || event.touches.length < 2) {
                return;
            }

            var container = map.getContainer();
            var p1 = getEventContainerPoint(event.touches[0], container),
                p2 = getEventContainerPoint(event.touches[1], container);
            this.preY = p1.y;
            this._startP1 = p1;
            this._startP2 = p2;
            this._startDist = p1.distanceTo(p2);
            this._startVector = p1.sub(p2);
            this._startZoom = map.getZoom();
            this._startBearing = map.getBearing();
            off(document, 'touchmove', this._onTouchMove, this);
            off(document, 'touchend', this._onTouchEnd, this);
            addDomEvent(document, 'touchmove', this._onTouchMove, this);
            addDomEvent(document, 'touchend', this._onTouchEnd, this);
            preventDefault(event);

            map._fireEvent('touchactstart');
        };

        _proto._onTouchMove = function _onTouchMove(event) {
            var map = this.target;

            if (!event.touches || event.touches.length < 2) {
                return;
            }

            var container = map.getContainer(),
                p1 = getEventContainerPoint(event.touches[0], container),
                p2 = getEventContainerPoint(event.touches[1], container),
                d1 = p1.sub(this._startP1),
                d2 = p2.sub(this._startP2),
                vector = p1.sub(p2),
                scale = p1.distanceTo(p2) / this._startDist,
                bearing = vector.angleWith(this._startVector) * 180 / Math.PI,
                preY = this.preY || p1.y,
                pitch = (preY - p1.y) * 0.4;

            this.preY = p1.y;
            var param = {
                'domEvent': event,
                'mousePos': [p1, p2]
            };

            if (!this.mode) {
                if (map.options['touchRotate'] && Math.abs(bearing) > 8) {
                    this.mode = map.options['touchZoomRotate'] ? 'rotate_zoom' : 'rotate';
                } else if (map.options['touchPitch'] && d1.y * d2.y > 0 && Math.abs(d1.y) > 10 && Math.abs(d2.y) > 10) {
                    this.mode = 'pitch';
                } else if (map.options['zoomable'] && map.options['touchZoom'] && Math.abs(1 - scale) > 0.15) {
                    this.mode = map.options['touchZoomRotate'] && map.options['touchRotate'] ? 'rotate_zoom' : 'zoom';
                }

                this._startTouching(param);
            }

            if (this.mode === 'zoom' || this.mode === 'rotate_zoom') {
                this._scale = scale;
                var res = map._getResolution(this._startZoom) / scale;
                var zoom = map.getZoomFromRes(res);
                map.onZooming(zoom, this._Origin);
            }

            if (this.mode === 'rotate' || this.mode === 'rotate_zoom') {
                map.setBearing(this._startBearing + bearing);
                map.onDragRotating(param);
            } else if (this.mode === 'pitch') {
                map.setPitch(map.getPitch() + pitch);
                map.onDragRotating(param);
            }

            map._fireEvent('touchactinging');
        };

        _proto._startTouching = function _startTouching(param) {
            var map = this.target;

            if (this.mode === 'zoom' || this.mode === 'rotate_zoom') {
                var size = map.getSize();
                this._Origin = new Point(size['width'] / 2, size['height'] / 2);
                map.onZoomStart(null, this._Origin);
            }

            if (this.mode === 'rotate' || this.mode === 'pitch' || this.mode === 'rotate_zoom') {
                map.onDragRotateStart(param);
            }
        };

        _proto._onTouchEnd = function _onTouchEnd(event) {
            delete this.preY;
            var map = this.target;
            off(document, 'touchmove', this._onTouchMove, this);
            off(document, 'touchend', this._onTouchEnd, this);

            if (this.mode === 'zoom' || this.mode === 'rotate_zoom') {
                var scale = this._scale;
                var res = map._getResolution(this._startZoom) / scale;
                var zoom = map.getZoomFromRes(res);
                map.onZoomEnd(zoom, this._Origin);
            }

            if (this.mode === 'pitch' || this.mode === 'rotate' || this.mode === 'rotate_zoom') {
                map.onDragRotateEnd({
                    'domEvent': event
                });
            }

            delete this.mode;

            map._fireEvent('touchactend');
        };

        return MapTouchZoomHandler;
    }(Handler$1);

    Map$1.mergeOptions({
        'touchGesture': true,
        'touchZoom': true,
        'touchPitch': true,
        'touchRotate': true,
        'touchZoomRotate': false
    });
    Map$1.addOnLoadHook('addHandler', 'touchGesture', MapTouchZoomHandler);

    var KEY = '__anim_player';
    var Easing = { in: function _in(t) {
            return Math.pow(t, 2);
        },
        out: function out(t) {
            return 1 - Easing.in(1 - t);
        },
        inAndOut: function inAndOut(t) {
            return 3 * t * t - 2 * t * t * t;
        },
        linear: function linear(t) {
            return t;
        },
        upAndDown: function upAndDown(t) {
            if (t < 0.5) {
                return Easing.inAndOut(2 * t);
            } else {
                return 1 - Easing.inAndOut(2 * (t - 0.5));
            }
        }
    };

    var Frame = function Frame(state, styles) {
        this.state = state;
        this.styles = styles;
    };

    var Player = function Player(animation, options, onFrame, target) {
        this._animation = animation;
        this.options = options;
        this._onFrame = onFrame;
        this.playState = 'idle';
        this.ready = true;
        this.finished = false;
        this.target = target;
    };

    var Animation = {
        speed: {
            'slow': 2000,
            'normal': 1000,
            'fast': 500
        },
        _resolveStyles: function _resolveStyles(styles) {
            if (!styles) {
                return null;
            }

            function resolveChild(child) {
                if (!Array.isArray(child)) {
                    return Animation._resolveStyles(child);
                }

                var start = [],
                    d = [],
                    dest = [];

                for (var i = 0; i < child.length; i++) {
                    var _styles = Animation._resolveStyles(child[i]);

                    if (_styles) {
                        start.push(_styles[0]);
                        d.push(_styles[1]);
                        dest.push(_styles[2]);
                    }
                }

                if (!start.length) {
                    return null;
                } else {
                    return [start, d, dest];
                }
            }

            function resolveVal(val) {
                var values = val;
                var clazz;

                if (!Array.isArray(val)) {
                    if (isNumber(val)) {
                        values = [0, val];
                    } else if (val instanceof Point || val instanceof Coordinate) {
                        clazz = val.constructor;
                        values = [new clazz(0, 0), val];
                    } else {
                        values = [val, val];
                    }
                }

                var v1 = values[0],
                    v2 = values[1];

                if (isNumber(v1) && isNumber(v2)) {
                    if (v1 === v2) {
                        return null;
                    }

                    return [v1, v2 - v1, v2];
                } else if (Array.isArray(v1) && isNumber(v1[0]) || v1 instanceof Coordinate || v1 instanceof Point) {
                    if (Array.isArray(v1)) {
                        v1 = new Coordinate(v1);
                        v2 = new Coordinate(v2);
                    } else {
                        clazz = v1.constructor;
                        v1 = new clazz(v1);
                        v2 = new clazz(v2);
                    }

                    if (v1.equals(v2)) {
                        return null;
                    }

                    return [v1, v2.sub(v1), v2];
                } else {
                    return [v1, v2, v2];
                }
            }

            function isChild(val) {
                if (!Array.isArray(val) && val.constructor === Object) {
                    return true;
                } else if (Array.isArray(val) && val[0].constructor === Object) {
                    return true;
                }

                return false;
            }

            var d = {},
                start = {},
                dest = {};

            for (var p in styles) {
                if (styles.hasOwnProperty(p)) {
                    var values = styles[p];

                    if (!values) {
                        continue;
                    } else if (Array.isArray(values)) {
                        if (isNil(values[0]) || isNil(values[1])) {
                            continue;
                        }
                    }

                    var childStyles = void 0;

                    if (isChild(values)) {
                        childStyles = resolveChild(values);
                    } else {
                        childStyles = resolveVal(values);
                    }

                    if (childStyles) {
                        start[p] = childStyles[0];
                        d[p] = childStyles[1];
                        dest[p] = childStyles[2];
                    }
                }
            }

            return [start, d, dest];
        },
        framing: function framing(styles, options) {
            if (!options) {
                options = {};
            }

            var easing = options['easing'] ? Easing[options['easing']] : Easing.linear;

            if (!easing) {
                easing = Easing.linear;
            }

            var dStyles, startStyles, destStyles;
            styles = Animation._resolveStyles(styles);

            if (styles) {
                startStyles = styles[0];
                dStyles = styles[1];
                destStyles = styles[2];
            }

            var deltaStyles = function deltaStyles(delta, _startStyles, _dStyles) {
                if (!_startStyles || !_dStyles) {
                    return null;
                }

                var result = {};

                for (var p in _dStyles) {
                    if (_dStyles.hasOwnProperty(p)) {
                        if (_startStyles[p] === destStyles[p]) {
                            result[p] = _startStyles[p];
                            continue;
                        }

                        var s = _startStyles[p],
                            d = _dStyles[p];

                        if (isNumber(d)) {
                            result[p] = s + delta * d;
                        } else if (Array.isArray(d)) {
                            var children = [];

                            for (var i = 0; i < d.length; i++) {
                                children.push(deltaStyles(delta, s[i], d[i]));
                            }

                            result[p] = children;
                        } else {
                            var clazz = d.constructor;

                            if (clazz === Object) {
                                result[p] = deltaStyles(delta, s, d);
                            } else if (s instanceof Point || s instanceof Coordinate) {
                                result[p] = s.add(d.multi(delta));
                            } else {
                                result[p] = d;
                            }
                        }
                    }
                }

                return result;
            };

            return function(elapsed, duration) {
                var state, d;

                if (elapsed < 0) {
                    state = {
                        'playState': 'idle',
                        'delta': 0
                    };
                    d = startStyles;
                } else if (elapsed < duration) {
                    var delta = easing(elapsed / duration);
                    state = {
                        'playState': 'running',
                        'delta': delta
                    };
                    d = deltaStyles(delta, startStyles, dStyles);
                } else {
                    state = {
                        'playState': 'finished',
                        'delta': 1
                    };
                    d = destStyles;
                }

                state['startStyles'] = startStyles;
                state['destStyles'] = destStyles;
                state['progress'] = elapsed;
                state['remainingMs'] = duration - elapsed;
                return new Frame(state, d);
            };
        },
        _requestAnimFrame: function _requestAnimFrame(fn) {
            if (!this._frameQueue) {
                this._frameQueue = [];
            }

            this._frameQueue.push(fn);

            this._a();
        },
        _a: function _a() {
            if (!this._animationFrameId) {
                this._animationFrameId = requestAnimFrame(Animation._frameFn);
            }
        },
        _run: function _run() {
            if (this._frameQueue.length) {
                var running = this._frameQueue;
                this._frameQueue = [];

                for (var i = 0, len = running.length; i < len; i++) {
                    running[i]();
                }

                if (this._frameQueue.length) {
                    this._animationFrameId = requestAnimFrame(Animation._frameFn);
                } else {
                    delete this._animationFrameId;
                }
            }
        },
        animate: function animate(styles, options, step, target) {
            if (!options) {
                options = {};
            }

            var animation = Animation.framing(styles, options);
            var player = new Player(animation, options, step, target);
            return player;
        }
    };
    Animation._frameFn = Animation._run.bind(Animation);
    extend(Player.prototype, {
        _prepare: function _prepare() {
            var options = this.options;
            var duration = options['speed'] || options['duration'];

            if (isString(duration)) {
                duration = Animation.speed[duration];

                if (!duration) {
                    duration = +duration;
                }
            }

            if (!duration) {
                duration = Animation.speed['normal'];
            }

            this.duration = duration;
            this._framer = options['framer'] || Animation._requestAnimFrame.bind(Animation);
        },
        play: function play() {
            if (this.playState !== 'idle' && this.playState !== 'paused' || this.target && this.target[KEY]) {
                return this;
            }

            if (this.target) {
                this.target[KEY] = 1;
            }

            if (this.playState === 'idle') {
                this.currentTime = 0;

                this._prepare();
            }

            var t = now();

            if (!this.startTime) {
                var options = this.options;
                this.startTime = options['startTime'] ? options['startTime'] : t;
            }

            this._playStartTime = Math.max(t, this.startTime);

            if (this.playState === 'paused') {
                this._playStartTime -= this.currentTime;
            }

            this.playState = 'running';

            this._run();

            return this;
        },
        pause: function pause() {
            if (this.playState === 'paused') {
                return this;
            }

            this.playState = 'paused';

            this._run();

            return this;
        },
        cancel: function cancel() {
            if (this.playState === 'idle') {
                return this;
            }

            this.playState = 'idle';
            this.finished = false;

            this._run();

            return this;
        },
        finish: function finish() {
            if (this.playState === 'finished') {
                return this;
            }

            this.playState = 'finished';
            this.finished = true;

            this._run();

            return this;
        },
        reverse: function reverse() {},
        _run: function _run() {
            var _this = this;

            var onFrame = this._onFrame;
            var t = now();
            var elapsed = t - this._playStartTime;

            if (this.options['repeat'] && elapsed >= this.duration) {
                this._playStartTime = t;
                elapsed = 0;
            }

            if (this.playState !== 'running') {
                if (this.target) {
                    delete this.target[KEY];
                }

                if (onFrame) {
                    if (this.playState === 'finished') {
                        elapsed = this.duration;
                    } else if (this.playState === 'idle') {
                        elapsed = 0;
                    }

                    var _frame = this._animation(elapsed, this.duration);

                    _frame.state.playState = this.playState;
                    onFrame(_frame);
                }

                return;
            }

            var frame = this._animation(elapsed, this.duration);

            this.playState = frame.state['playState'];

            if (this.playState !== 'running' && this.target) {
                delete this.target[KEY];
            }

            if (this.playState === 'idle') {
                if (this.startTime > t) {
                    setTimeout(this._run.bind(this), this.startTime - t);
                }
            } else if (this.playState === 'running') {
                this._framer(function() {
                    if (_this.playState !== 'running') {
                        return;
                    }

                    _this.currentTime = elapsed;

                    if (onFrame) {
                        onFrame(frame);
                    }

                    _this._run();
                });
            } else if (this.playState === 'finished') {
                this.finished = true;

                if (onFrame) {
                    onFrame(frame);
                }
            }
        }
    });

    var Animation$1 = /*#__PURE__*/ Object.freeze({
        Animation: Animation,
        Easing: Easing,
        Player: Player,
        Frame: Frame
    });

    var simplify = createCommonjsModule(function(module) {
        (function() {

            function getSqDist(p1, p2) {
                var dx = p1.x - p2.x,
                    dy = p1.y - p2.y;
                return dx * dx + dy * dy;
            }

            function getSqSegDist(p, p1, p2) {
                var x = p1.x,
                    y = p1.y,
                    dx = p2.x - x,
                    dy = p2.y - y;

                if (dx !== 0 || dy !== 0) {
                    var t = ((p.x - x) * dx + (p.y - y) * dy) / (dx * dx + dy * dy);

                    if (t > 1) {
                        x = p2.x;
                        y = p2.y;
                    } else if (t > 0) {
                        x += dx * t;
                        y += dy * t;
                    }
                }

                dx = p.x - x;
                dy = p.y - y;
                return dx * dx + dy * dy;
            }

            function simplifyRadialDist(points, sqTolerance) {
                var prevPoint = points[0],
                    newPoints = [prevPoint],
                    point;

                for (var i = 1, len = points.length; i < len; i++) {
                    point = points[i];

                    if (getSqDist(point, prevPoint) > sqTolerance) {
                        newPoints.push(point);
                        prevPoint = point;
                    }
                }

                if (prevPoint !== point) newPoints.push(point);
                return newPoints;
            }

            function simplifyDPStep(points, first, last, sqTolerance, simplified) {
                var maxSqDist = sqTolerance,
                    index;

                for (var i = first + 1; i < last; i++) {
                    var sqDist = getSqSegDist(points[i], points[first], points[last]);

                    if (sqDist > maxSqDist) {
                        index = i;
                        maxSqDist = sqDist;
                    }
                }

                if (maxSqDist > sqTolerance) {
                    if (index - first > 1) simplifyDPStep(points, first, index, sqTolerance, simplified);
                    simplified.push(points[index]);
                    if (last - index > 1) simplifyDPStep(points, index, last, sqTolerance, simplified);
                }
            }

            function simplifyDouglasPeucker(points, sqTolerance) {
                var last = points.length - 1;
                var simplified = [points[0]];
                simplifyDPStep(points, 0, last, sqTolerance, simplified);
                simplified.push(points[last]);
                return simplified;
            }

            function simplify(points, tolerance, highestQuality) {
                if (points.length <= 2) return points;
                var sqTolerance = tolerance !== undefined ? tolerance * tolerance : 1;
                points = highestQuality ? points : simplifyRadialDist(points, sqTolerance);
                points = simplifyDouglasPeucker(points, sqTolerance);
                return points;
            }

            {
                module.exports = simplify;
                module.exports.default = simplify;
            }
        })();
    });

    var options$3 = {
        'smoothness': 0,
        'enableClip': true,
        'enableSimplify': true,
        'simplifyTolerance': 2,
        'symbol': {
            'lineColor': '#000',
            'lineWidth': 2,
            'lineOpacity': 1,
            'polygonFill': '#fff',
            'polygonOpacity': 1,
            'opacity': 1
        }
    };

    var Path = function(_Geometry) {
        _inheritsLoose(Path, _Geometry);

        function Path() {
            return _Geometry.apply(this, arguments) || this;
        }

        var _proto = Path.prototype;

        _proto.getOutline = function getOutline() {
            var painter = this._getPainter();

            if (!painter) {
                return null;
            }

            var extent = this.getExtent();
            return new Polygon(extent.toArray(), {
                symbol: {
                    'lineWidth': 1,
                    'lineColor': '6b707b'
                }
            });
        };

        _proto.animateShow = function animateShow(options, cb) {
            var _this = this;

            if (options === void 0) {
                options = {};
            }

            if (this._showPlayer) {
                this._showPlayer.finish();
            }

            if (isFunction(options)) {
                options = {};
                cb = options;
            }

            var coordinates = this.getCoordinates();

            if (coordinates.length === 0) {
                return this;
            }

            this._animIdx = 0;
            this._animLenSoFar = 0;
            this.show();
            var isPolygon = !!this.getShell;
            var animCoords = isPolygon ? this.getShell().concat(this.getShell()[0]) : this.getCoordinates();

            var projection = this._getProjection();

            var prjAnimCoords = projection.projectCoords(animCoords);
            this._prjAniShowCenter = this._getPrjExtent().getCenter();
            this._aniShowCenter = projection.unproject(this._prjAniShowCenter);
            var duration = options['duration'] || 1000,
                easing = options['easing'] || 'out';
            this.setCoordinates([]);
            var length = 0;

            for (var i = 1; i < prjAnimCoords.length; i++) {
                length += prjAnimCoords[i].distanceTo(prjAnimCoords[i - 1]);
            }

            var player = this._showPlayer = Animation.animate({
                't': duration
            }, {
                'duration': duration,
                'easing': easing
            }, function(frame) {
                if (!_this.getMap()) {
                    if (player.playState !== 'finished') {
                        player.finish();

                        if (cb) {
                            var _coordinates = _this.getCoordinates();

                            cb(frame, _coordinates[_coordinates.length - 1]);
                        }
                    }

                    return;
                }

                var currentCoord = _this._drawAnimShowFrame(frame.styles.t, duration, length, animCoords, prjAnimCoords);

                if (frame.state.playState === 'finished') {
                    delete _this._showPlayer;
                    delete _this._aniShowCenter;
                    delete _this._prjAniShowCenter;
                    delete _this._animIdx;
                    delete _this._animLenSoFar;
                    delete _this._animTailRatio;

                    _this.setCoordinates(coordinates);
                }

                if (cb) {
                    cb(frame, currentCoord);
                }
            }, this);
            player.play();
            return player;
        };

        _proto._drawAnimShowFrame = function _drawAnimShowFrame(t, duration, length, coordinates, prjCoords) {
            if (t === 0) {
                return coordinates[0];
            }

            var projection = this._getProjection();

            var targetLength = t / duration * length;
            var segLen = 0;
            var i, l;

            for (i = this._animIdx, l = prjCoords.length; i < l - 1; i++) {
                segLen = prjCoords[i].distanceTo(prjCoords[i + 1]);

                if (this._animLenSoFar + segLen > targetLength) {
                    break;
                }

                this._animLenSoFar += segLen;
            }

            this._animIdx = i;

            if (this._animIdx >= l - 1) {
                this.setCoordinates(coordinates);
                return coordinates[coordinates.length - 1];
            }

            var idx = this._animIdx;
            var p1 = prjCoords[idx],
                p2 = prjCoords[idx + 1],
                span = targetLength - this._animLenSoFar,
                r = span / segLen;
            this._animTailRatio = r;
            var x = p1.x + (p2.x - p1.x) * r,
                y = p1.y + (p2.y - p1.y) * r,
                lastCoord = new Coordinate(x, y);
            var targetCoord = projection.unproject(lastCoord);
            var isPolygon = !!this.getShell;

            if (!isPolygon && this.options['smoothness'] > 0) {
                var animCoords = coordinates.slice(0, this._animIdx + 3);
                this.setCoordinates(animCoords);
                var prjAnimCoords = prjCoords.slice(0, this._animIdx + 3);

                this._setPrjCoordinates(prjAnimCoords);
            } else {
                var _animCoords = coordinates.slice(0, this._animIdx + 1);

                _animCoords.push(targetCoord);

                var _prjAnimCoords = prjCoords.slice(0, this._animIdx + 1);

                _prjAnimCoords.push(lastCoord);

                if (isPolygon) {
                    this.setCoordinates([this._aniShowCenter].concat(_animCoords));

                    this._setPrjCoordinates([this._prjAniShowCenter].concat(_prjAnimCoords));
                } else {
                    this.setCoordinates(_animCoords);

                    this._setPrjCoordinates(_prjAnimCoords);
                }
            }

            return targetCoord;
        };

        _proto._getCenterInExtent = function _getCenterInExtent(extent, coordinates, clipFn) {
            var meExtent = this.getExtent();

            if (!extent.intersects(meExtent)) {
                return null;
            }

            var clipped = clipFn(coordinates, extent);

            if (clipped.length === 0) {
                return null;
            }

            var sumx = 0,
                sumy = 0,
                counter = 0;
            clipped.forEach(function(part) {
                if (Array.isArray(part)) {
                    part.forEach(function(c) {
                        if (c.point) {
                            c = c.point;
                        }

                        sumx += c.x;
                        sumy += c.y;
                        counter++;
                    });
                } else {
                    if (part.point) {
                        part = part.point;
                    }

                    sumx += part.x;
                    sumy += part.y;
                    counter++;
                }
            });

            var c = new Coordinate(sumx, sumy)._multi(1 / counter);

            c.count = counter;
            return c;
        };

        _proto._getPath2DPoints = function _getPath2DPoints(prjCoords, disableSimplify, zoom) {
            if (!isArrayHasData(prjCoords)) {
                return [];
            }

            var map = this.getMap(),
                isSimplify = !disableSimplify && this._shouldSimplify(),
                tolerance = this.options['simplifyTolerance'] * map._getResolution(),
                isMulti = Array.isArray(prjCoords[0]);

            delete this._simplified;

            if (isSimplify && !isMulti) {
                var count = prjCoords.length;
                prjCoords = simplify(prjCoords, tolerance, false);
                this._simplified = prjCoords.length < count;
            }

            if (isNil(zoom)) {
                zoom = map.getZoom();
            }

            return forEachCoord(prjCoords, function(c) {
                return map._prjToPoint(c, zoom);
            });
        };

        _proto._shouldSimplify = function _shouldSimplify() {
            var layer = this.getLayer(),
                properties = this.getProperties();
            var hasAltitude = properties && layer.options['enableAltitude'] && !isNil(properties[layer.options['altitudeProperty']]);
            return layer && layer.options['enableSimplify'] && !hasAltitude && this.options['enableSimplify'] && !this._showPlayer;
        };

        _proto._setPrjCoordinates = function _setPrjCoordinates(prjPoints) {
            this._prjCoords = prjPoints;
            this.onShapeChanged();
        };

        _proto._getPrjCoordinates = function _getPrjCoordinates() {
            this._verifyProjection();

            if (!this._prjCoords && this._getProjection()) {
                this._prjCoords = this._projectCoords(this._coordinates);
            }

            return this._prjCoords;
        };

        _proto._updateCache = function _updateCache() {
            this._clearCache();

            var projection = this._getProjection();

            if (!projection) {
                return;
            }

            if (this._prjCoords) {
                this._coordinates = this._unprojectCoords(this._getPrjCoordinates());
            }
        };

        _proto._clearProjection = function _clearProjection() {
            this._prjCoords = null;

            _Geometry.prototype._clearProjection.call(this);
        };

        _proto._projectCoords = function _projectCoords(points) {
            var projection = this._getProjection();

            if (projection) {
                return projection.projectCoords(points);
            }

            return [];
        };

        _proto._unprojectCoords = function _unprojectCoords(prjPoints) {
            var projection = this._getProjection();

            if (projection) {
                return projection.unprojectCoords(prjPoints);
            }

            return [];
        };

        _proto._computeCenter = function _computeCenter() {
            var ring = this._coordinates;

            if (!isArrayHasData(ring)) {
                return null;
            }

            var sumx = 0,
                sumy = 0,
                counter = 0;
            var size = ring.length;

            for (var i = 0; i < size; i++) {
                if (ring[i]) {
                    if (isNumber(ring[i].x) && isNumber(ring[i].y)) {
                        sumx += ring[i].x;
                        sumy += ring[i].y;
                        counter++;
                    }
                }
            }

            return new Coordinate(sumx / counter, sumy / counter);
        };

        _proto._computeExtent = function _computeExtent() {
            var shell = this._coordinates;

            if (!isArrayHasData(shell)) {
                return null;
            }

            var rings = [shell];

            if (this.hasHoles && this.hasHoles()) {
                rings.push.apply(rings, this.getHoles());
            }

            return this._coords2Extent(rings, this._getProjection());
        };

        _proto._computePrjExtent = function _computePrjExtent() {
            var coords = [this._getPrjCoordinates()];

            if (this.hasHoles && this.hasHoles()) {
                coords.push.apply(coords, this._getPrjHoles());
            }

            return this._coords2Extent(coords);
        };

        _proto._get2DLength = function _get2DLength() {
            var vertexes = this._getPath2DPoints(this._getPrjCoordinates(), true);

            var len = 0;

            for (var i = 1, l = vertexes.length; i < l; i++) {
                len += vertexes[i].distanceTo(vertexes[i - 1]);
            }

            return len;
        };

        _proto._hitTestTolerance = function _hitTestTolerance() {
            var symbol = this._getInternalSymbol();

            var w;

            if (Array.isArray(symbol)) {
                w = 0;

                for (var i = 0; i < symbol.length; i++) {
                    if (isNumber(symbol[i]['lineWidth'])) {
                        if (symbol[i]['lineWidth'] > w) {
                            w = symbol[i]['lineWidth'];
                        }
                    }
                }
            } else {
                w = symbol['lineWidth'];
            }

            return isNumber(w) ? w / 2 : 1.5;
        };

        _proto._coords2Extent = function _coords2Extent(coords, proj) {
            var result = new Extent(proj);

            for (var i = 0, l = coords.length; i < l; i++) {
                for (var j = 0, ll = coords[i].length; j < ll; j++) {
                    result._combine(coords[i][j]);
                }
            }

            return result;
        };

        return Path;
    }(Geometry);

    Path.mergeOptions(options$3);

    var JSON_TYPE = 'Polygon';

    var Polygon = function(_Path) {
        _inheritsLoose(Polygon, _Path);

        function Polygon(coordinates, opts) {
            var _this;

            _this = _Path.call(this, opts) || this;
            _this.type = 'Polygon';

            if (coordinates) {
                _this.setCoordinates(coordinates);
            }

            return _this;
        }

        var _proto = Polygon.prototype;

        _proto.setCoordinates = function setCoordinates(coordinates) {
            if (!coordinates) {
                this._coordinates = null;
                this._holes = null;

                this._projectRings();

                return this;
            }

            var rings = Coordinate.toCoordinates(coordinates);
            var len = rings.length;

            if (!Array.isArray(rings[0])) {
                this._coordinates = this._trimRing(rings);
            } else {
                this._coordinates = this._trimRing(rings[0]);

                if (len > 1) {
                    var holes = [];

                    for (var i = 1; i < len; i++) {
                        if (!rings[i]) {
                            continue;
                        }

                        holes.push(this._trimRing(rings[i]));
                    }

                    this._holes = holes;
                }
            }

            this._projectRings();

            return this;
        };

        _proto.getCoordinates = function getCoordinates() {
            if (!this._coordinates) {
                return [];
            }

            var holes = this.getHoles();
            var rings = [this._copyAndCloseRing(this._coordinates)];

            for (var i = 0, l = holes.length; i < l; i++) {
                rings.push(this._copyAndCloseRing(holes[i]));
            }

            return rings;
        };

        _proto.getCenterInExtent = function getCenterInExtent(extent) {
            return this._getCenterInExtent(extent, this.getShell(), clipPolygon);
        };

        _proto.getShell = function getShell() {
            return this._coordinates || [];
        };

        _proto.getHoles = function getHoles() {
            return this._holes || [];
        };

        _proto.hasHoles = function hasHoles() {
            return this.getHoles().length > 0;
        };

        _proto._projectRings = function _projectRings() {
            if (!this.getMap()) {
                this.onShapeChanged();
                return;
            }

            this._prjCoords = this._projectCoords(this._coordinates);
            this._prjHoles = this._projectCoords(this._holes);
            this.onShapeChanged();
        };

        _proto._setPrjCoordinates = function _setPrjCoordinates(prjCoords) {
            this._prjCoords = prjCoords;
            this.onShapeChanged();
        };

        _proto._cleanRing = function _cleanRing(ring) {
            for (var i = ring.length - 1; i >= 0; i--) {
                if (!ring[i]) {
                    ring.splice(i, 1);
                }
            }
        };

        _proto._checkRing = function _checkRing(ring) {
            this._cleanRing(ring);

            if (!ring || !isArrayHasData(ring)) {
                return false;
            }

            var lastPoint = ring[ring.length - 1];
            var isClose = true;

            if (ring[0].x !== lastPoint.x || ring[0].y !== lastPoint.y) {
                isClose = false;
            }

            return isClose;
        };

        _proto._trimRing = function _trimRing(ring) {
            var isClose = this._checkRing(ring);

            if (isArrayHasData(ring) && isClose) {
                ring.splice(ring.length - 1, 1);
            }

            return ring;
        };

        _proto._copyAndCloseRing = function _copyAndCloseRing(ring) {
            ring = ring.slice(0);

            var isClose = this._checkRing(ring);

            if (isArrayHasData(ring) && !isClose) {
                ring.push(ring[0].copy());
                return ring;
            } else {
                return ring;
            }
        };

        _proto._getPrjShell = function _getPrjShell() {
            if (this.getJSONType() === JSON_TYPE) {
                return this._getPrjCoordinates();
            }

            this._verifyProjection();

            if (this._getProjection() && !this._prjShell) {
                this._prjShell = this._projectCoords(this.getShell());
            }

            return this._prjShell;
        };

        _proto._getPrjHoles = function _getPrjHoles() {
            var projection = this._getProjection();

            this._verifyProjection();

            if (projection && !this._prjHoles) {
                this._prjHoles = this._projectCoords(this.getHoles());
            }

            return this._prjHoles;
        };

        _proto._computeGeodesicLength = function _computeGeodesicLength(measurer) {
            var rings = this.getCoordinates();

            if (!isArrayHasData(rings)) {
                return 0;
            }

            var result = 0;

            for (var i = 0, len = rings.length; i < len; i++) {
                result += measurer.measureLength(rings[i]);
            }

            return result;
        };

        _proto._computeGeodesicArea = function _computeGeodesicArea(measurer) {
            var rings = this.getCoordinates();

            if (!isArrayHasData(rings)) {
                return 0;
            }

            var result = measurer.measureArea(rings[0]);

            for (var i = 1, len = rings.length; i < len; i++) {
                result -= measurer.measureArea(rings[i]);
            }

            return result;
        };

        _proto._updateCache = function _updateCache() {
            _Path.prototype._updateCache.call(this);

            if (this._prjHoles) {
                this._holes = this._unprojectCoords(this._getPrjHoles());
            }
        };

        _proto._clearCache = function _clearCache() {
            delete this._prjShell;
            return _Path.prototype._clearCache.call(this);
        };

        _proto._clearProjection = function _clearProjection() {
            if (this._prjHoles) {
                this._prjHoles = null;
            }

            if (this._prjShell) {
                this._prjShell = null;
            }

            _Path.prototype._clearProjection.call(this);
        };

        return Polygon;
    }(Path);

    Polygon.registerJSONType(JSON_TYPE);

    function CenterMixin(Base) {
        return function(_Base) {
            _inheritsLoose(_class, _Base);

            function _class() {
                return _Base.apply(this, arguments) || this;
            }

            var _proto = _class.prototype;

            _proto.getCoordinates = function getCoordinates() {
                return this._coordinates;
            };

            _proto.setCoordinates = function setCoordinates(coordinates) {
                var center = coordinates instanceof Coordinate ? coordinates : new Coordinate(coordinates);

                if (center.equals(this._coordinates)) {
                    return this;
                }

                this._coordinates = center;

                if (!this.getMap()) {
                    this.onPositionChanged();
                    return this;
                }

                var projection = this._getProjection();

                this._setPrjCoordinates(projection.project(this._coordinates));

                return this;
            };

            _proto._getCenter2DPoint = function _getCenter2DPoint(zoom) {
                var map = this.getMap();

                if (!map) {
                    return null;
                }

                var z = isNil(zoom) ? map.getZoom() : map.getGLZoom();

                var pcenter = this._getPrjCoordinates();

                if (!pcenter) {
                    return null;
                }

                return map._prjToPoint(pcenter, z);
            };

            _proto._getPrjCoordinates = function _getPrjCoordinates() {
                var projection = this._getProjection();

                this._verifyProjection();

                if (!this._pcenter && projection) {
                    if (this._coordinates) {
                        this._pcenter = projection.project(this._coordinates);
                    }
                }

                return this._pcenter;
            };

            _proto._setPrjCoordinates = function _setPrjCoordinates(pcenter) {
                this._pcenter = pcenter;
                this.onPositionChanged();
            };

            _proto._updateCache = function _updateCache() {
                this._clearCache();

                var projection = this._getProjection();

                if (this._pcenter && projection) {
                    this._coordinates = projection.unproject(this._pcenter);
                }
            };

            _proto._clearProjection = function _clearProjection() {
                this._pcenter = null;

                _Base.prototype._clearProjection.call(this);
            };

            _proto._computeCenter = function _computeCenter() {
                return this._coordinates ? this._coordinates.copy() : null;
            };

            return _class;
        }(Base);
    }

    var options$4 = {
        'symbol': {
            'markerType': 'path',
            'markerPath': [{
                'path': 'M8 23l0 0 0 0 0 0 0 0 0 0c-4,-5 -8,-10 -8,-14 0,-5 4,-9 8,-9l0 0 0 0c4,0 8,4 8,9 0,4 -4,9 -8,14z M3,9 a5,5 0,1,0,0,-0.9Z',
                'fill': '#DE3333'
            }],
            'markerPathWidth': 16,
            'markerPathHeight': 23,
            'markerWidth': 24,
            'markerHeight': 34
        },
        'hitTestForEvent': false
    };

    var Marker = function(_CenterMixin) {
        _inheritsLoose(Marker, _CenterMixin);

        function Marker(coordinates, opts) {
            var _this;

            _this = _CenterMixin.call(this, opts) || this;
            _this.type = 'Point';

            if (coordinates) {
                _this.setCoordinates(coordinates);
            }

            return _this;
        }

        var _proto = Marker.prototype;

        _proto.getOutline = function getOutline() {
            var painter = this._getPainter();

            if (!painter) {
                return null;
            }

            var coord = this.getCoordinates();
            var extent = painter.getContainerExtent();
            var anchor = this.getMap().coordToContainerPoint(coord);
            return new Marker(coord, {
                'symbol': {
                    'markerType': 'square',
                    'markerWidth': extent.getWidth(),
                    'markerHeight': extent.getHeight(),
                    'markerLineWidth': 1,
                    'markerLineColor': '6b707b',
                    'markerFill': 'rgba(0, 0, 0, 0)',
                    'markerDx': extent.xmin - (anchor.x - extent.getWidth() / 2),
                    'markerDy': extent.ymin - (anchor.y - extent.getHeight() / 2)
                }
            });
        };

        _proto._isVectorMarker = function _isVectorMarker() {
            var symbol = this._getInternalSymbol();

            if (Array.isArray(symbol)) {
                return false;
            }

            return VectorMarkerSymbolizer.test(symbol);
        };

        _proto._canEdit = function _canEdit() {
            var symbol = this._getInternalSymbol();

            if (Array.isArray(symbol)) {
                return false;
            }

            return VectorMarkerSymbolizer.test(symbol) || VectorPathMarkerSymbolizer.test(symbol) || ImageMarkerSymbolizer.test(symbol);
        };

        _proto._containsPoint = function _containsPoint(point, t) {
            var extent = this.getContainerExtent();

            if (t) {
                extent = extent.expand(t);
            }

            if (extent.contains(point)) {
                if (this.options['hitTestForEvent']) {
                    return _CenterMixin.prototype._containsPoint.call(this, point, t);
                } else {
                    return true;
                }
            } else {
                return false;
            }
        };

        _proto._computeExtent = function _computeExtent() {
            return computeExtent.call(this, 'getCenter');
        };

        _proto._computePrjExtent = function _computePrjExtent() {
            return computeExtent.call(this, '_getPrjCoordinates');
        };

        _proto._computeGeodesicLength = function _computeGeodesicLength() {
            return 0;
        };

        _proto._computeGeodesicArea = function _computeGeodesicArea() {
            return 0;
        };

        _proto._getSprite = function _getSprite(resources, canvasClass) {
            if (this._getPainter()) {
                return this._getPainter().getSprite(resources, canvasClass);
            }

            return new Painter(this).getSprite(resources, canvasClass);
        };

        return Marker;
    }(CenterMixin(Geometry));

    Marker.mergeOptions(options$4);
    Marker.registerJSONType('Marker');

    function computeExtent(fn) {
        var coordinates = this[fn]();

        if (!coordinates) {
            return null;
        }

        return new Extent(coordinates, coordinates, this._getProjection());
    }

    var options$5 = {
        'arrowStyle': null,
        'arrowPlacement': 'vertex-last'
    };

    var LineString = function(_Path) {
        _inheritsLoose(LineString, _Path);

        function LineString(coordinates, options) {
            var _this;

            _this = _Path.call(this, options) || this;
            _this.type = 'LineString';

            if (coordinates) {
                _this.setCoordinates(coordinates);
            }

            return _this;
        }

        var _proto = LineString.prototype;

        _proto.setCoordinates = function setCoordinates(coordinates) {
            if (!coordinates) {
                this._coordinates = null;

                this._setPrjCoordinates(null);

                return this;
            }

            this._coordinates = Coordinate.toCoordinates(coordinates);

            if (this.getMap()) {
                this._setPrjCoordinates(this._projectCoords(this._coordinates));
            } else {
                this.onShapeChanged();
            }

            return this;
        };

        _proto.getCoordinates = function getCoordinates() {
            return this._coordinates || [];
        };

        _proto.getCenterInExtent = function getCenterInExtent(extent) {
            return this._getCenterInExtent(extent, this.getCoordinates(), clipLine);
        };

        _proto._computeGeodesicLength = function _computeGeodesicLength(measurer) {
            return measurer.measureLength(this.getCoordinates());
        };

        _proto._computeGeodesicArea = function _computeGeodesicArea() {
            return 0;
        };

        return LineString;
    }(Path);

    LineString.mergeOptions(options$5);
    LineString.registerJSONType('LineString');

    var GeometryCollection = function(_Geometry) {
        _inheritsLoose(GeometryCollection, _Geometry);

        function GeometryCollection(geometries, opts) {
            var _this;

            _this = _Geometry.call(this, opts) || this;
            _this.type = 'GeometryCollection';

            _this.setGeometries(geometries);

            return _this;
        }

        var _proto = GeometryCollection.prototype;

        _proto.setGeometries = function setGeometries(_geometries) {
            var geometries = this._checkGeometries(_geometries || []);

            var symbol = this._getSymbol();

            var options = this.config();

            for (var i = geometries.length - 1; i >= 0; i--) {
                geometries[i]._initOptions(options);

                geometries[i]._setParent(this);

                geometries[i]._setEventParent(this);

                if (symbol) {
                    geometries[i].setSymbol(symbol);
                }
            }

            this._geometries = geometries;

            if (this.getLayer()) {
                this._bindGeometriesToLayer();

                this.onShapeChanged();
            }

            return this;
        };

        _proto.getGeometries = function getGeometries() {
            return this._geometries || [];
        };

        _proto.forEach = function forEach(fn, context) {
            var geometries = this.getGeometries();

            for (var i = 0, l = geometries.length; i < l; i++) {
                if (!geometries[i]) {
                    continue;
                }

                if (!context) {
                    fn(geometries[i], i);
                } else {
                    fn.call(context, geometries[i], i);
                }
            }

            return this;
        };

        _proto.filter = function filter(fn, context) {
            if (!fn) {
                return new GeometryCollection();
            }

            var selected = [];
            var isFn = isFunction(fn);
            var filter = isFn ? fn : createFilter(fn);
            this.forEach(function(geometry) {
                var g = isFn ? geometry : getFilterFeature(geometry);

                if (context ? filter.call(context, g) : filter(g)) {
                    selected.push(geometry);
                }
            }, this);
            return new GeometryCollection(selected);
        };

        _proto.translate = function translate(offset) {
            if (!offset) {
                return this;
            }

            if (this.isEmpty()) {
                return this;
            }

            var args = arguments;
            this.forEach(function(geometry) {
                if (geometry && geometry.translate) {
                    geometry.translate.apply(geometry, args);
                }
            });
            return this;
        };

        _proto.isEmpty = function isEmpty$$1() {
            return !isArrayHasData(this.getGeometries());
        };

        _proto.remove = function remove() {
            this.forEach(function(geometry) {
                geometry._unbind();
            });
            return Geometry.prototype.remove.apply(this, arguments);
        };

        _proto.show = function show() {
            this.options['visible'] = true;
            this.forEach(function(geometry) {
                geometry.show();
            });
            return this;
        };

        _proto.hide = function hide() {
            this.options['visible'] = false;
            this.forEach(function(geometry) {
                geometry.hide();
            });
            return this;
        };

        _proto.onConfig = function onConfig(config) {
            this.forEach(function(geometry) {
                geometry.config(config);
            });
        };

        _proto.getSymbol = function getSymbol() {
            var s = _Geometry.prototype.getSymbol.call(this);

            if (!s) {
                var symbols = [];
                var is = false;
                this.forEach(function(g) {
                    var symbol = g.getSymbol();

                    if (symbol && !is) {
                        is = true;
                    }

                    symbols.push(g.getSymbol());
                });

                if (is) {
                    s = {
                        'children': symbols
                    };
                }
            }

            return s;
        };

        _proto.setSymbol = function setSymbol(s) {
            if (s && s['children']) {
                this._symbol = null;
                this.forEach(function(g, i) {
                    g.setSymbol(s['children'][i]);
                });
            } else {
                var symbol = this._prepareSymbol(s);

                this._symbol = symbol;
                this.forEach(function(g) {
                    g.setSymbol(symbol);
                });
            }

            this.onSymbolChanged();
            return this;
        };

        _proto._setExternSymbol = function _setExternSymbol(symbol) {
            symbol = this._prepareSymbol(symbol);
            this._externSymbol = symbol;
            this.forEach(function(geometry) {
                geometry._setExternSymbol(symbol);
            });
            this.onSymbolChanged();
            return this;
        };

        _proto._bindLayer = function _bindLayer() {
            _Geometry.prototype._bindLayer.apply(this, arguments);

            this._bindGeometriesToLayer();
        };

        _proto._bindGeometriesToLayer = function _bindGeometriesToLayer() {
            var layer = this.getLayer();
            this.forEach(function(geometry) {
                geometry._bindLayer(layer);
            });
        };

        _proto._checkGeometries = function _checkGeometries(geometries) {
            var invalidGeoError = 'The geometry added to collection is invalid.';

            if (geometries && !Array.isArray(geometries)) {
                if (geometries instanceof Geometry) {
                    return [geometries];
                } else {
                    throw new Error(invalidGeoError);
                }
            } else {
                for (var i = 0, l = geometries.length; i < l; i++) {
                    if (!this._checkGeo(geometries[i])) {
                        throw new Error(invalidGeoError + ' Index: ' + i);
                    }
                }

                return geometries;
            }
        };

        _proto._checkGeo = function _checkGeo(geo) {
            return geo instanceof Geometry;
        };

        _proto._updateCache = function _updateCache() {
            this._clearCache();

            if (this.isEmpty()) {
                return;
            }

            this.forEach(function(geometry) {
                if (geometry && geometry._updateCache) {
                    geometry._updateCache();
                }
            });
        };

        _proto._removePainter = function _removePainter() {
            if (this._painter) {
                this._painter.remove();
            }

            delete this._painter;
            this.forEach(function(geometry) {
                geometry._removePainter();
            });
        };

        _proto._computeCenter = function _computeCenter(projection) {
            if (!projection || this.isEmpty()) {
                return null;
            }

            var sumX = 0,
                sumY = 0,
                counter = 0;
            var geometries = this.getGeometries();

            for (var i = 0, l = geometries.length; i < l; i++) {
                if (!geometries[i]) {
                    continue;
                }

                var center = geometries[i]._computeCenter(projection);

                if (center) {
                    sumX += center.x;
                    sumY += center.y;
                    counter++;
                }
            }

            if (counter === 0) {
                return null;
            }

            return new Coordinate(sumX / counter, sumY / counter);
        };

        _proto._containsPoint = function _containsPoint(point, t) {
            if (this.isEmpty()) {
                return false;
            }

            var geometries = this.getGeometries();

            for (var i = 0, l = geometries.length; i < l; i++) {
                if (geometries[i]._containsPoint(point, t)) {
                    return true;
                }
            }

            return false;
        };

        _proto._computeExtent = function _computeExtent(projection) {
            return computeExtent$1.call(this, projection, '_computeExtent');
        };

        _proto._computePrjExtent = function _computePrjExtent(projection) {
            return computeExtent$1.call(this, projection, '_computePrjExtent');
        };

        _proto._computeGeodesicLength = function _computeGeodesicLength(projection) {
            if (!projection || this.isEmpty()) {
                return 0;
            }

            var geometries = this.getGeometries();
            var result = 0;

            for (var i = 0, l = geometries.length; i < l; i++) {
                if (!geometries[i]) {
                    continue;
                }

                result += geometries[i]._computeGeodesicLength(projection);
            }

            return result;
        };

        _proto._computeGeodesicArea = function _computeGeodesicArea(projection) {
            if (!projection || this.isEmpty()) {
                return 0;
            }

            var geometries = this.getGeometries();
            var result = 0;

            for (var i = 0, l = geometries.length; i < l; i++) {
                if (!geometries[i]) {
                    continue;
                }

                result += geometries[i]._computeGeodesicArea(projection);
            }

            return result;
        };

        _proto._exportGeoJSONGeometry = function _exportGeoJSONGeometry() {
            var children = [];

            if (!this.isEmpty()) {
                var geometries = this.getGeometries();

                for (var i = 0, l = geometries.length; i < l; i++) {
                    if (!geometries[i]) {
                        continue;
                    }

                    children.push(geometries[i]._exportGeoJSONGeometry());
                }
            }

            return {
                'type': 'GeometryCollection',
                'geometries': children
            };
        };

        _proto._clearProjection = function _clearProjection() {
            if (this.isEmpty()) {
                return;
            }

            var geometries = this.getGeometries();

            for (var i = 0, l = geometries.length; i < l; i++) {
                if (!geometries[i]) {
                    continue;
                }

                geometries[i]._clearProjection();
            }
        };

        _proto._getConnectPoints = function _getConnectPoints() {
            var extent = this.getExtent();
            var anchors = [new Coordinate(extent.xmin, extent.ymax), new Coordinate(extent.xmax, extent.ymin), new Coordinate(extent.xmin, extent.ymin), new Coordinate(extent.xmax, extent.ymax)];
            return anchors;
        };

        _proto._getExternalResources = function _getExternalResources() {
            if (this.isEmpty()) {
                return [];
            }

            var geometries = this.getGeometries(),
                resources = [];
            var cache = {};
            var symbol, res, key;

            for (var i = 0, l = geometries.length; i < l; i++) {
                if (!geometries[i]) {
                    continue;
                }

                symbol = geometries[i]._getInternalSymbol();
                res = getExternalResources(symbol);

                for (var ii = 0, ll = res.length; ii < ll; ii++) {
                    key = res[ii].join();

                    if (!cache[key]) {
                        resources.push(res[ii]);
                        cache[key] = 1;
                    }
                }
            }

            return resources;
        };

        _proto.startEdit = function startEdit(opts) {
            var _this2 = this;

            if (this.isEmpty()) {
                return this;
            }

            if (!opts) {
                opts = {};
            }

            if (opts['symbol']) {
                this._originalSymbol = this.getSymbol();
                this.setSymbol(opts['symbol']);
            }

            this._draggbleBeforeEdit = this.options['draggable'];
            this.config('draggable', false);
            var geometries = this.getGeometries();

            for (var i = 0, l = geometries.length; i < l; i++) {
                geometries[i].startEdit(opts);
            }

            this._editing = true;
            this.hide();
            setTimeout(function() {
                _this2.fire('editstart');
            }, 1);
            return this;
        };

        _proto.endEdit = function endEdit() {
            if (this.isEmpty()) {
                return this;
            }

            var geometries = this.getGeometries();

            for (var i = 0, l = geometries.length; i < l; i++) {
                geometries[i].endEdit();
            }

            if (this._originalSymbol) {
                this.setSymbol(this._originalSymbol);
                delete this._originalSymbol;
            }

            this._editing = false;
            this.show();
            this.config('draggable', this._draggbleBeforeEdit);
            this.fire('editend');
            return this;
        };

        _proto.isEditing = function isEditing() {
            if (!this._editing) {
                return false;
            }

            return true;
        };

        return GeometryCollection;
    }(Geometry);

    GeometryCollection.registerJSONType('GeometryCollection');

    function computeExtent$1(projection, fn) {
        if (this.isEmpty()) {
            return null;
        }

        var geometries = this.getGeometries();
        var result = null;

        for (var i = 0, l = geometries.length; i < l; i++) {
            var geo = geometries[i];

            if (!geo) {
                continue;
            }

            var geoExtent = geo[fn](projection);

            if (geoExtent) {
                result = geoExtent.combine(result);
            }
        }

        return result;
    }

    var MultiGeometry = function(_GeometryCollection) {
        _inheritsLoose(MultiGeometry, _GeometryCollection);

        function MultiGeometry(geoType, type, data, options) {
            var _this;

            _this = _GeometryCollection.call(this, null, options) || this;
            _this.GeometryType = geoType;
            _this.type = type;

            _this._initData(data);

            return _this;
        }

        var _proto = MultiGeometry.prototype;

        _proto.getCoordinates = function getCoordinates() {
            var coordinates = [];
            var geometries = this.getGeometries();

            for (var i = 0, l = geometries.length; i < l; i++) {
                var child = geometries[i];
                coordinates.push(child.getShell && child.getJSONType() !== 'Polygon' ? [child.getShell()] : child.getCoordinates());
            }

            return coordinates;
        };

        _proto.setCoordinates = function setCoordinates(coordinates) {
            coordinates = coordinates || [];
            var geometries = [];

            for (var i = 0, l = coordinates.length; i < l; i++) {
                var g = new this.GeometryType(coordinates[i], this.config());
                geometries.push(g);
            }

            this.setGeometries(geometries);
            return this;
        };

        _proto._initData = function _initData(data) {
            data = data || [];

            if (data.length) {
                if (data[0] instanceof this.GeometryType) {
                    this.setGeometries(data);
                } else {
                    this.setCoordinates(data);
                }
            }
        };

        _proto._checkGeo = function _checkGeo(geo) {
            return geo instanceof this.GeometryType;
        };

        _proto._exportGeoJSONGeometry = function _exportGeoJSONGeometry() {
            var points = this.getCoordinates();
            var coordinates = Coordinate.toNumberArrays(points);
            return {
                'type': this.getType(),
                'coordinates': coordinates
            };
        };

        return MultiGeometry;
    }(GeometryCollection);

    var MultiPoint = function(_MultiGeometry) {
        _inheritsLoose(MultiPoint, _MultiGeometry);

        function MultiPoint(data, opts) {
            return _MultiGeometry.call(this, Marker, 'MultiPoint', data, opts) || this;
        }

        var _proto = MultiPoint.prototype;

        _proto.findClosest = function findClosest(coordinate) {
            if (!coordinate) {
                return null;
            }

            var coords = this.getCoordinates();
            var hit = null;
            var max = Infinity;
            coords.forEach(function(c) {
                var dist = distanceTo(c, coordinate);

                if (dist < max) {
                    hit = c;
                    max = dist;
                }
            });
            return hit;
        };

        return MultiPoint;
    }(MultiGeometry);

    MultiPoint.registerJSONType('MultiPoint');

    function distanceTo(p0, p1) {
        var x = p1.x - p0.x,
            y = p1.y - p0.y;
        return Math.sqrt(x * x + y * y);
    }

    var MultiPath = function(_MultiGeometry) {
        _inheritsLoose(MultiPath, _MultiGeometry);

        function MultiPath() {
            return _MultiGeometry.apply(this, arguments) || this;
        }

        var _proto = MultiPath.prototype;

        _proto.getCenterInExtent = function getCenterInExtent(extent) {
            var children = this.getGeometries();
            var sumx = 0,
                sumy = 0,
                counter = 0;
            children.forEach(function(l) {
                var c = l.getCenterInExtent(extent);

                if (c) {
                    sumx += c.x * c.count;
                    sumy += c.y * c.count;
                    counter += c.count;
                }
            });

            if (counter === 0) {
                return null;
            }

            return new Coordinate(sumx, sumy)._multi(1 / counter);
        };

        return MultiPath;
    }(MultiGeometry);

    var MultiLineString = function(_MultiPath) {
        _inheritsLoose(MultiLineString, _MultiPath);

        function MultiLineString(data, options) {
            return _MultiPath.call(this, LineString, 'MultiLineString', data, options) || this;
        }

        return MultiLineString;
    }(MultiPath);

    MultiLineString.registerJSONType('MultiLineString');

    var MultiPolygon = function(_MultiPath) {
        _inheritsLoose(MultiPolygon, _MultiPath);

        function MultiPolygon(data, opts) {
            return _MultiPath.call(this, Polygon, 'MultiPolygon', data, opts) || this;
        }

        return MultiPolygon;
    }(MultiPath);

    MultiPolygon.registerJSONType('MultiPolygon');

    var types$1 = {
        'Marker': Marker,
        'LineString': LineString,
        'Polygon': Polygon,
        'MultiPoint': MultiPoint,
        'MultiLineString': MultiLineString,
        'MultiPolygon': MultiPolygon
    };
    var GeoJSON = {
        toGeometry: function toGeometry(geoJSON, foreachFn) {
            if (isString(geoJSON)) {
                geoJSON = parseJSON(geoJSON);
            }

            if (Array.isArray(geoJSON)) {
                var resultGeos = [];

                for (var i = 0, len = geoJSON.length; i < len; i++) {
                    var geo = GeoJSON._convert(geoJSON[i], foreachFn);

                    if (Array.isArray(geo)) {
                        pushIn(resultGeos, geo);
                    } else {
                        resultGeos.push(geo);
                    }
                }

                return resultGeos;
            } else {
                var resultGeo = GeoJSON._convert(geoJSON, foreachFn);

                return resultGeo;
            }
        },
        _convert: function _convert(json, foreachFn) {
            if (!json || isNil(json['type'])) {
                return null;
            }

            var type = json['type'];

            if (type === 'Feature') {
                var g = json['geometry'];

                var geometry = GeoJSON._convert(g);

                if (!geometry) {
                    return null;
                }

                geometry.setId(json['id']);
                geometry.setProperties(json['properties']);

                if (foreachFn) {
                    foreachFn(geometry);
                }

                return geometry;
            } else if (type === 'FeatureCollection') {
                var features = json['features'];

                if (!features) {
                    return null;
                }

                return GeoJSON.toGeometry(features, foreachFn);
            } else if (['Point', 'LineString', 'Polygon', 'MultiPoint', 'MultiLineString', 'MultiPolygon'].indexOf(type) >= 0) {
                var clazz = type === 'Point' ? 'Marker' : type;
                var result = new types$1[clazz](json['coordinates']);

                if (foreachFn) {
                    foreachFn(result);
                }

                return result;
            } else if (type === 'GeometryCollection') {
                var geometries = json['geometries'];

                if (!isArrayHasData(geometries)) {
                    var _result2 = new GeometryCollection();

                    if (foreachFn) {
                        foreachFn(_result2);
                    }

                    return _result2;
                }

                var mGeos = [];
                var size = geometries.length;

                for (var i = 0; i < size; i++) {
                    mGeos.push(GeoJSON._convert(geometries[i]));
                }

                var _result = new GeometryCollection(mGeos);

                if (foreachFn) {
                    foreachFn(_result);
                }

                return _result;
            }

            return null;
        }
    };

    var options$6 = {
        'numberOfShellPoints': 60
    };

    var Circle = function(_CenterMixin) {
        _inheritsLoose(Circle, _CenterMixin);

        Circle.fromJSON = function fromJSON(json) {
            var feature = json['feature'];
            var circle = new Circle(json['coordinates'], json['radius'], json['options']);
            circle.setProperties(feature['properties']);
            return circle;
        };

        function Circle(coordinates, radius, opts) {
            var _this;

            _this = _CenterMixin.call(this, null, opts) || this;

            if (coordinates) {
                _this.setCoordinates(coordinates);
            }

            _this._radius = radius;
            return _this;
        }

        var _proto = Circle.prototype;

        _proto.getRadius = function getRadius() {
            return this._radius;
        };

        _proto.setRadius = function setRadius(radius) {
            this._radius = radius;
            this.onShapeChanged();
            return this;
        };

        _proto.getShell = function getShell() {
            var measurer = this._getMeasurer(),
                center = this.getCoordinates(),
                numberOfPoints = this.options['numberOfShellPoints'],
                radius = this.getRadius();

            var shell = [];
            var rad, dx, dy;

            for (var i = 0, len = numberOfPoints - 1; i < len; i++) {
                rad = 360 * i / len * Math.PI / 180;
                dx = radius * Math.cos(rad);
                dy = radius * Math.sin(rad);
                var vertex = measurer.locate(center, dx, dy);
                shell.push(vertex);
            }

            shell.push(shell[0]);
            return shell;
        };

        _proto.getHoles = function getHoles() {
            return [];
        };

        _proto.animateShow = function animateShow() {
            return this.show();
        };

        _proto._containsPoint = function _containsPoint(point, tolerance) {
            var map = this.getMap();

            if (map.getPitch()) {
                return _CenterMixin.prototype._containsPoint.call(this, point, tolerance);
            }

            var center = map._pointToContainerPoint(this._getCenter2DPoint()),
                size = this.getSize(),
                t = isNil(tolerance) ? this._hitTestTolerance() : tolerance,
                se = center.add(size.width / 2, size.height / 2);

            return withInEllipse(point, center, se, t);
        };

        _proto._computePrjExtent = function _computePrjExtent(projection) {
            var minmax = this._getMinMax(projection);

            if (!minmax) {
                return null;
            }

            var pcenter = this._getPrjCoordinates();

            var pminmax = minmax.map(function(c) {
                return projection.project(c);
            });
            var leftx = pminmax[0].x - pcenter.x;
            var rightx = pminmax[1].x - pcenter.x;
            var topy = pminmax[2].y - pcenter.y;
            var bottomy = pminmax[3].y - pcenter.y;
            return new Extent(pcenter.add(leftx, topy), pcenter.add(rightx, bottomy));
        };

        _proto._computeExtent = function _computeExtent(measurer) {
            var minmax = this._getMinMax(measurer);

            if (!minmax) {
                return null;
            }

            return new Extent(minmax[0].x, minmax[2].y, minmax[1].x, minmax[3].y, this._getProjection());
        };

        _proto._getMinMax = function _getMinMax(measurer) {
            if (!measurer || !this._coordinates || isNil(this._radius)) {
                return null;
            }

            var radius = this._radius;
            var p1 = measurer.locate(this._coordinates, -radius, 0),
                p2 = measurer.locate(this._coordinates, radius, 0),
                p3 = measurer.locate(this._coordinates, 0, radius),
                p4 = measurer.locate(this._coordinates, 0, -radius);
            return [p1, p2, p3, p4];
        };

        _proto._computeGeodesicLength = function _computeGeodesicLength() {
            if (isNil(this._radius)) {
                return 0;
            }

            return Math.PI * 2 * this._radius;
        };

        _proto._computeGeodesicArea = function _computeGeodesicArea() {
            if (isNil(this._radius)) {
                return 0;
            }

            return Math.PI * Math.pow(this._radius, 2);
        };

        _proto._exportGeoJSONGeometry = function _exportGeoJSONGeometry() {
            var coordinates = Coordinate.toNumberArrays([this.getShell()]);
            return {
                'type': 'Polygon',
                'coordinates': coordinates
            };
        };

        _proto._toJSON = function _toJSON(options) {
            var center = this.getCenter();
            var opts = extend({}, options);
            opts.geometry = false;
            var feature = this.toGeoJSON(opts);
            feature['geometry'] = {
                'type': 'Polygon'
            };
            return {
                'feature': feature,
                'subType': 'Circle',
                'coordinates': [center.x, center.y],
                'radius': this.getRadius()
            };
        };

        return Circle;
    }(CenterMixin(Polygon));

    Circle.mergeOptions(options$6);
    Circle.registerJSONType('Circle');

    var options$7 = {
        'numberOfShellPoints': 80
    };

    var Ellipse = function(_CenterMixin) {
        _inheritsLoose(Ellipse, _CenterMixin);

        Ellipse.fromJSON = function fromJSON(json) {
            var feature = json['feature'];
            var ellipse = new Ellipse(json['coordinates'], json['width'], json['height'], json['options']);
            ellipse.setProperties(feature['properties']);
            return ellipse;
        };

        function Ellipse(coordinates, width, height, opts) {
            var _this;

            _this = _CenterMixin.call(this, null, opts) || this;

            if (coordinates) {
                _this.setCoordinates(coordinates);
            }

            _this.width = width;
            _this.height = height;
            return _this;
        }

        var _proto = Ellipse.prototype;

        _proto.getWidth = function getWidth() {
            return this.width;
        };

        _proto.setWidth = function setWidth(width) {
            this.width = width;
            this.onShapeChanged();
            return this;
        };

        _proto.getHeight = function getHeight() {
            return this.height;
        };

        _proto.setHeight = function setHeight(height) {
            this.height = height;
            this.onShapeChanged();
            return this;
        };

        _proto.getShell = function getShell() {
            var measurer = this._getMeasurer(),
                center = this.getCoordinates(),
                numberOfPoints = this.options['numberOfShellPoints'],
                width = this.getWidth(),
                height = this.getHeight();

            var shell = [];
            var s = Math.pow(width / 2, 2) * Math.pow(height / 2, 2),
                sx = Math.pow(width / 2, 2),
                sy = Math.pow(height / 2, 2);
            var deg, rad, dx, dy;

            for (var i = 0; i < numberOfPoints; i++) {
                deg = 360 * i / numberOfPoints;
                rad = deg * Math.PI / 180;
                dx = Math.sqrt(s / (sx * Math.pow(Math.tan(rad), 2) + sy));
                dy = Math.sqrt(s / (sy * Math.pow(1 / Math.tan(rad), 2) + sx));

                if (deg > 90 && deg < 270) {
                    dx *= -1;
                }

                if (deg > 180 && deg < 360) {
                    dy *= -1;
                }

                var vertex = measurer.locate(center, dx, dy);
                shell.push(vertex);
            }

            return shell;
        };

        _proto.getHoles = function getHoles() {
            return [];
        };

        _proto.animateShow = function animateShow() {
            return this.show();
        };

        _proto._containsPoint = function _containsPoint(point, tolerance) {
            var map = this.getMap();

            if (map.isTransforming()) {
                return _CenterMixin.prototype._containsPoint.call(this, point, tolerance);
            }

            var projection = map.getProjection();

            var t = isNil(tolerance) ? this._hitTestTolerance() : tolerance,
                pps = projection.projectCoords([this._coordinates, map.locate(this._coordinates, this.getWidth() / 2, this.getHeight() / 2)]),
                p0 = map._prjToContainerPoint(pps[0]),
                p1 = map._prjToContainerPoint(pps[1]);

            return withInEllipse(point, p0, p1, t);
        };

        _proto._computePrjExtent = function _computePrjExtent() {
            return Circle.prototype._computePrjExtent.apply(this, arguments);
        };

        _proto._computeExtent = function _computeExtent() {
            return Circle.prototype._computeExtent.apply(this, arguments);
        };

        _proto._getMinMax = function _getMinMax(measurer) {
            if (!measurer || !this._coordinates || isNil(this.width) || isNil(this.height)) {
                return null;
            }

            var width = this.getWidth(),
                height = this.getHeight();
            var p1 = measurer.locate(this._coordinates, -width / 2, 0),
                p2 = measurer.locate(this._coordinates, width / 2, 0),
                p3 = measurer.locate(this._coordinates, 0, -height / 2),
                p4 = measurer.locate(this._coordinates, 0, height / 2);
            return [p1, p2, p3, p4];
        };

        _proto._computeGeodesicLength = function _computeGeodesicLength() {
            if (isNil(this.width) || isNil(this.height)) {
                return 0;
            }

            var longer = this.width > this.height ? this.width : this.height;
            return 2 * Math.PI * longer / 2 - 4 * Math.abs(this.width - this.height);
        };

        _proto._computeGeodesicArea = function _computeGeodesicArea() {
            if (isNil(this.width) || isNil(this.height)) {
                return 0;
            }

            return Math.PI * this.width * this.height / 4;
        };

        _proto._exportGeoJSONGeometry = function _exportGeoJSONGeometry() {
            var coordinates = Coordinate.toNumberArrays([this.getShell()]);
            return {
                'type': 'Polygon',
                'coordinates': coordinates
            };
        };

        _proto._toJSON = function _toJSON(options) {
            var opts = extend({}, options);
            var center = this.getCenter();
            opts.geometry = false;
            var feature = this.toGeoJSON(opts);
            feature['geometry'] = {
                'type': 'Polygon'
            };
            return {
                'feature': feature,
                'subType': 'Ellipse',
                'coordinates': [center.x, center.y],
                'width': this.getWidth(),
                'height': this.getHeight()
            };
        };

        return Ellipse;
    }(CenterMixin(Polygon));

    Ellipse.mergeOptions(options$7);
    Ellipse.registerJSONType('Ellipse');

    var Rectangle = function(_Polygon) {
        _inheritsLoose(Rectangle, _Polygon);

        Rectangle.fromJSON = function fromJSON(json) {
            var feature = json['feature'];
            var rect = new Rectangle(json['coordinates'], json['width'], json['height'], json['options']);
            rect.setProperties(feature['properties']);
            return rect;
        };

        function Rectangle(coordinates, width, height, opts) {
            var _this;

            _this = _Polygon.call(this, null, opts) || this;

            if (coordinates) {
                _this.setCoordinates(coordinates);
            }

            _this._width = width;
            _this._height = height;
            return _this;
        }

        var _proto = Rectangle.prototype;

        _proto.getCoordinates = function getCoordinates() {
            return this._coordinates;
        };

        _proto.setCoordinates = function setCoordinates(nw) {
            this._coordinates = nw instanceof Coordinate ? nw : new Coordinate(nw);

            if (!this._coordinates || !this.getMap()) {
                this.onPositionChanged();
                return this;
            }

            var projection = this._getProjection();

            this._setPrjCoordinates(projection.project(this._coordinates));

            return this;
        };

        _proto.getWidth = function getWidth() {
            return this._width;
        };

        _proto.setWidth = function setWidth(width) {
            this._width = width;
            this.onShapeChanged();
            return this;
        };

        _proto.getHeight = function getHeight() {
            return this._height;
        };

        _proto.setHeight = function setHeight(height) {
            this._height = height;
            this.onShapeChanged();
            return this;
        };

        _proto.getShell = function getShell() {
            var measurer = this._getMeasurer();

            var nw = this._coordinates;
            var map = this.getMap();
            var sx = 1,
                sy = -1;

            if (map) {
                var fExt = map.getFullExtent();

                if (fExt['left'] > fExt['right']) {
                    sx = -1;
                }

                if (fExt['bottom'] > fExt['top']) {
                    sy = 1;
                }
            }

            var points = [];
            points.push(nw);
            points.push(measurer.locate(nw, sx * this._width, 0));
            points.push(measurer.locate(nw, sx * this._width, sy * this._height));
            points.push(measurer.locate(nw, 0, sy * this._height));
            points.push(nw);
            return points;
        };

        _proto.getHoles = function getHoles() {
            return [];
        };

        _proto.animateShow = function animateShow() {
            return this.show();
        };

        _proto._getPrjCoordinates = function _getPrjCoordinates() {
            var projection = this._getProjection();

            this._verifyProjection();

            if (!this._pnw && projection) {
                if (this._coordinates) {
                    this._pnw = projection.project(this._coordinates);
                }
            }

            return this._pnw;
        };

        _proto._setPrjCoordinates = function _setPrjCoordinates(pnw) {
            this._pnw = pnw;
            this.onPositionChanged();
        };

        _proto._getPrjShell = function _getPrjShell() {
            var shell = _Polygon.prototype._getPrjShell.call(this);

            var projection = this._getProjection();

            if (!projection.isSphere()) {
                return shell;
            }

            var sphereExtent = projection.getSphereExtent(),
                sx = sphereExtent.sx,
                sy = sphereExtent.sy;

            var circum = this._getProjection().getCircum();

            var nw = shell[0];

            for (var i = 1, l = shell.length; i < l; i++) {
                var p = shell[i];
                var dx = 0,
                    dy = 0;

                if (sx * (nw.x - p.x) > 0) {
                    dx = circum.x * sx;
                }

                if (sy * (nw.y - p.y) < 0) {
                    dy = circum.y * sy;
                }

                shell[i]._add(dx, dy);
            }

            return shell;
        };

        _proto._updateCache = function _updateCache() {
            this._clearCache();

            var projection = this._getProjection();

            if (this._pnw && projection) {
                this._coordinates = projection.unproject(this._pnw);
            }
        };

        _proto._clearProjection = function _clearProjection() {
            this._pnw = null;

            _Polygon.prototype._clearProjection.call(this);
        };

        _proto._computeCenter = function _computeCenter(measurer) {
            return measurer.locate(this._coordinates, this._width / 2, -this._height / 2);
        };

        _proto._containsPoint = function _containsPoint(point, tolerance) {
            var map = this.getMap();

            if (map.isTransforming()) {
                return _Polygon.prototype._containsPoint.call(this, point, tolerance);
            }

            var t = isNil(tolerance) ? this._hitTestTolerance() : tolerance,
                r = map._getResolution() * t;

            var extent = this._getPrjExtent().expand(r);

            var p = map._containerPointToPrj(point);

            return extent.contains(p);
        };

        _proto._computePrjExtent = function _computePrjExtent(projection) {
            var se = this._getSouthEast(projection);

            if (!se) {
                return null;
            }

            var prjs = projection.projectCoords([new Coordinate(this._coordinates.x, se.y), new Coordinate(se.x, this._coordinates.y)]);
            return new Extent(prjs[0], prjs[1]);
        };

        _proto._computeExtent = function _computeExtent(measurer) {
            var se = this._getSouthEast(measurer);

            if (!se) {
                return null;
            }

            return new Extent(this._coordinates, se, this._getProjection());
        };

        _proto._getSouthEast = function _getSouthEast(measurer) {
            if (!measurer || !this._coordinates || isNil(this._width) || isNil(this._height)) {
                return null;
            }

            var width = this.getWidth(),
                height = this.getHeight();
            var w = width,
                h = -height;

            if (measurer.fullExtent) {
                var fullExtent = measurer.fullExtent,
                    sx = fullExtent.right > fullExtent.left ? 1 : -1,
                    sy = fullExtent.top > fullExtent.bottom ? 1 : -1;
                w *= sx;
                h *= sy;
            }

            var se = measurer.locate(this._coordinates, w, h);
            return se;
        };

        _proto._computeGeodesicLength = function _computeGeodesicLength() {
            if (isNil(this._width) || isNil(this._height)) {
                return 0;
            }

            return 2 * (this._width + this._height);
        };

        _proto._computeGeodesicArea = function _computeGeodesicArea() {
            if (isNil(this._width) || isNil(this._height)) {
                return 0;
            }

            return this._width * this._height;
        };

        _proto._exportGeoJSONGeometry = function _exportGeoJSONGeometry() {
            var coordinates = Coordinate.toNumberArrays([this.getShell()]);
            return {
                'type': 'Polygon',
                'coordinates': coordinates
            };
        };

        _proto._toJSON = function _toJSON(options) {
            var opts = extend({}, options);
            var nw = this.getCoordinates();
            opts.geometry = false;
            var feature = this.toGeoJSON(opts);
            feature['geometry'] = {
                'type': 'Polygon'
            };
            return {
                'feature': feature,
                'subType': 'Rectangle',
                'coordinates': [nw.x, nw.y],
                'width': this.getWidth(),
                'height': this.getHeight()
            };
        };

        return Rectangle;
    }(Polygon);

    Rectangle.registerJSONType('Rectangle');

    var options$8 = {
        'numberOfShellPoints': 60
    };

    var Sector = function(_Circle) {
        _inheritsLoose(Sector, _Circle);

        Sector.fromJSON = function fromJSON(json) {
            var feature = json['feature'];
            var sector = new Sector(json['coordinates'], json['radius'], json['startAngle'], json['endAngle'], json['options']);
            sector.setProperties(feature['properties']);
            return sector;
        };

        function Sector(coordinates, radius, startAngle, endAngle, opts) {
            var _this;

            _this = _Circle.call(this, coordinates, radius, opts) || this;
            _this.startAngle = startAngle;
            _this.endAngle = endAngle;
            return _this;
        }

        var _proto = Sector.prototype;

        _proto.getStartAngle = function getStartAngle() {
            return this.startAngle;
        };

        _proto.setStartAngle = function setStartAngle(startAngle) {
            this.startAngle = startAngle;
            this.onShapeChanged();
            return this;
        };

        _proto.getEndAngle = function getEndAngle() {
            return this.endAngle;
        };

        _proto.setEndAngle = function setEndAngle(endAngle) {
            this.endAngle = endAngle;
            this.onShapeChanged();
            return this;
        };

        _proto.getShell = function getShell() {
            var measurer = this._getMeasurer(),
                center = this.getCoordinates(),
                numberOfPoints = this.options['numberOfShellPoints'] - 2,
                radius = this.getRadius(),
                shell = [center.copy()],
                startAngle = this.getStartAngle(),
                angle = this.getEndAngle() - startAngle;

            var rad, dx, dy;

            for (var i = 0; i < numberOfPoints; i++) {
                rad = (angle * i / (numberOfPoints - 1) + startAngle) * Math.PI / 180;
                dx = radius * Math.cos(rad);
                dy = radius * Math.sin(rad);
                var vertex = measurer.locate(center, dx, dy);
                shell.push(vertex);
            }

            shell.push(center.copy());
            return shell;
        };

        _proto._containsPoint = function _containsPoint(point, tolerance) {
            var map = this.getMap();

            if (map.isTransforming()) {
                return _Circle.prototype._containsPoint.call(this, point, tolerance);
            }

            var center = map._pointToContainerPoint(this._getCenter2DPoint()),
                t = isNil(tolerance) ? this._hitTestTolerance() : tolerance,
                size = this.getSize(),
                pc = center,
                pp = point,
                x = pp.x - pc.x,
                y = pc.y - pp.y,
                atan2 = Math.atan2(y, x),
                angle = atan2 < 0 ? (atan2 + 2 * Math.PI) * 360 / (2 * Math.PI) : atan2 * 360 / (2 * Math.PI);

            var sAngle = this.startAngle % 360,
                eAngle = this.endAngle % 360;
            var between = false;

            if (sAngle > eAngle) {
                between = !(angle > eAngle && angle < sAngle);
            } else {
                between = angle >= sAngle && angle <= eAngle;
            }

            return pp.distanceTo(pc) <= size.width / 2 + t && between;
        };

        _proto._computeGeodesicLength = function _computeGeodesicLength() {
            if (isNil(this._radius)) {
                return 0;
            }

            return Math.PI * 2 * this._radius * Math.abs(this.startAngle - this.endAngle) / 360 + 2 * this._radius;
        };

        _proto._computeGeodesicArea = function _computeGeodesicArea() {
            if (isNil(this._radius)) {
                return 0;
            }

            return Math.PI * Math.pow(this._radius, 2) * Math.abs(this.startAngle - this.endAngle) / 360;
        };

        _proto._toJSON = function _toJSON(options) {
            var opts = extend({}, options);
            var center = this.getCenter();
            opts.geometry = false;
            var feature = this.toGeoJSON(opts);
            feature['geometry'] = {
                'type': 'Polygon'
            };
            return {
                'feature': feature,
                'subType': 'Sector',
                'coordinates': [center.x, center.y],
                'radius': this.getRadius(),
                'startAngle': this.getStartAngle(),
                'endAngle': this.getEndAngle()
            };
        };

        return Sector;
    }(Circle);

    Sector.mergeOptions(options$8);
    Sector.registerJSONType('Sector');

    var options$9 = {
        'enableSimplify': false,
        'enableClip': false
    };

    var Curve = function(_LineString) {
        _inheritsLoose(Curve, _LineString);

        function Curve() {
            return _LineString.apply(this, arguments) || this;
        }

        var _proto = Curve.prototype;

        _proto._arc = function _arc(ctx, points, lineOpacity) {
            var degree = this.options['arcDegree'] * Math.PI / 180;

            for (var i = 1, l = points.length; i < l; i++) {
                var c = Canvas._arcBetween(ctx, points[i - 1], points[i], degree);

                var ctrlPoint = [points[i - 1].x + points[i].x - c[0], points[i - 1].y + points[i].y - c[1]];
                points[i - 1].nextCtrlPoint = ctrlPoint;
                points[i].prevCtrlPoint = ctrlPoint;

                Canvas._stroke(ctx, lineOpacity);
            }
        };

        _proto._quadraticCurve = function _quadraticCurve(ctx, points) {
            if (points.length <= 2) {
                Canvas._path(ctx, points);

                return;
            }

            var i, l;

            for (i = 2, l = points.length; i < l; i += 2) {
                ctx.quadraticCurveTo(points[i - 1].x, points[i - 1].y, points[i].x, points[i].y);
            }

            i -= 1;

            if (i < l) {
                for (; i < l; i++) {
                    ctx.lineTo(points[i].x, points[i].y);
                }
            }
        };

        _proto._bezierCurve = function _bezierCurve(ctx, points) {
            if (points.length <= 3) {
                Canvas._path(ctx, points);

                return;
            }

            var i, l;

            for (i = 1, l = points.length; i + 2 < l; i += 3) {
                ctx.bezierCurveTo(points[i].x, points[i].y, points[i + 1].x, points[i + 1].y, points[i + 2].x, points[i + 2].y);
            }

            if (i < l) {
                for (; i < l; i++) {
                    ctx.lineTo(points[i].x, points[i].y);
                }
            }
        };

        _proto._getCurveArrowPoints = function _getCurveArrowPoints(arrows, segments, lineWidth, arrowStyle, tolerance, step) {
            var l = segments.length;
            var i;

            for (i = step; i < l; i += step) {
                var arrow = this._getArrowShape(segments[i - 1], segments[i], lineWidth, arrowStyle, tolerance);

                if (arrow) {
                    arrows.push(arrow);
                }
            }

            i -= step;

            if (i < l - 1) {
                for (i += 1; i < l; i++) {
                    var _arrow = this._getArrowShape(segments[i - 1], segments[i], lineWidth, arrowStyle, tolerance);

                    if (_arrow) {
                        arrows.push(_arrow);
                    }
                }
            }
        };

        return Curve;
    }(LineString);

    Curve.mergeOptions(options$9);

    var options$a = {
        'arcDegree': 90
    };

    var ArcCurve = function(_Curve) {
        _inheritsLoose(ArcCurve, _Curve);

        function ArcCurve() {
            return _Curve.apply(this, arguments) || this;
        }

        var _proto = ArcCurve.prototype;

        _proto._toJSON = function _toJSON(options) {
            return {
                'feature': this.toGeoJSON(options),
                'subType': 'ArcCurve'
            };
        };

        _proto._paintOn = function _paintOn(ctx, points, lineOpacity) {
            ctx.beginPath();

            this._arc(ctx, points, lineOpacity);

            Canvas._stroke(ctx, lineOpacity);

            this._paintArrow(ctx, points, lineOpacity);
        };

        ArcCurve.fromJSON = function fromJSON(json) {
            var feature = json['feature'];
            var arc = new ArcCurve(feature['geometry']['coordinates'], json['options']);
            arc.setProperties(feature['properties']);
            return arc;
        };

        return ArcCurve;
    }(Curve);

    ArcCurve.registerJSONType('ArcCurve');
    ArcCurve.mergeOptions(options$a);

    var CubicBezierCurve = function(_Curve) {
        _inheritsLoose(CubicBezierCurve, _Curve);

        function CubicBezierCurve() {
            return _Curve.apply(this, arguments) || this;
        }

        CubicBezierCurve.fromJSON = function fromJSON(json) {
            var feature = json['feature'];
            var curve = new CubicBezierCurve(feature['geometry']['coordinates'], json['options']);
            curve.setProperties(feature['properties']);
            return curve;
        };

        var _proto = CubicBezierCurve.prototype;

        _proto._toJSON = function _toJSON(options) {
            return {
                'feature': this.toGeoJSON(options),
                'subType': 'CubicBezierCurve'
            };
        };

        _proto._paintOn = function _paintOn(ctx, points, lineOpacity) {
            ctx.beginPath();
            ctx.moveTo(points[0].x, points[0].y);

            this._bezierCurve(ctx, points);

            Canvas._stroke(ctx, lineOpacity);

            this._paintArrow(ctx, points, lineOpacity);
        };

        _proto._getArrowPoints = function _getArrowPoints(arrows, segments, lineWidth, arrowStyle, tolerance) {
            return this._getCurveArrowPoints(arrows, segments, lineWidth, arrowStyle, tolerance, 3);
        };

        return CubicBezierCurve;
    }(Curve);

    CubicBezierCurve.registerJSONType('CubicBezierCurve');

    var QuadBezierCurve = function(_Curve) {
        _inheritsLoose(QuadBezierCurve, _Curve);

        function QuadBezierCurve() {
            return _Curve.apply(this, arguments) || this;
        }

        QuadBezierCurve.fromJSON = function fromJSON(json) {
            var feature = json['feature'];
            var curve = new QuadBezierCurve(feature['geometry']['coordinates'], json['options']);
            curve.setProperties(feature['properties']);
            return curve;
        };

        var _proto = QuadBezierCurve.prototype;

        _proto._toJSON = function _toJSON(options) {
            return {
                'feature': this.toGeoJSON(options),
                'subType': 'QuadBezierCurve'
            };
        };

        _proto._paintOn = function _paintOn(ctx, points, lineOpacity) {
            ctx.beginPath();
            ctx.moveTo(points[0].x, points[0].y);

            this._quadraticCurve(ctx, points, lineOpacity);

            Canvas._stroke(ctx, lineOpacity);

            this._paintArrow(ctx, points, lineOpacity);
        };

        _proto._getArrowPoints = function _getArrowPoints(arrows, segments, lineWidth, arrowStyle, tolerance) {
            return this._getCurveArrowPoints(arrows, segments, lineWidth, arrowStyle, tolerance, 2);
        };

        return QuadBezierCurve;
    }(Curve);

    QuadBezierCurve.registerJSONType('QuadBezierCurve');

    var defaultSymbol$1 = {
        'textFaceName': 'monospace',
        'textSize': 12,
        'textLineSpacing': 8,
        'textWrapCharacter': '\n',
        'textHorizontalAlignment': 'middle',
        'textVerticalAlignment': 'middle'
    };
    var defaultBoxSymbol = {
        'markerType': 'square',
        'markerLineColor': '#000',
        'markerLineWidth': 2,
        'markerLineOpacity': 1,
        'markerFill': '#fff',
        'markerOpacity': 1
    };

    var TextMarker = function(_Marker) {
        _inheritsLoose(TextMarker, _Marker);

        function TextMarker() {
            return _Marker.apply(this, arguments) || this;
        }

        var _proto = TextMarker.prototype;

        _proto.getContent = function getContent() {
            return this._content;
        };

        _proto.setContent = function setContent(content) {
            var old = this._content;
            this._content = escapeSpecialChars(content);

            this._refresh();

            this._fireEvent('contentchange', {
                'old': old,
                'new': content
            });

            return this;
        };

        _proto.onAdd = function onAdd() {
            this._refresh();
        };

        _proto.toJSON = function toJSON() {
            var json = _Marker.prototype.toJSON.call(this);

            delete json['symbol'];
            return json;
        };

        _proto.setSymbol = function setSymbol(symbol) {
            if (this._refreshing || !symbol) {
                return _Marker.prototype.setSymbol.call(this, symbol);
            }

            var s = this._parseSymbol(symbol);

            if (this.setTextStyle) {
                var style = this.getTextStyle() || {};
                style.symbol = s[0];
                this.setTextStyle(style);
            } else if (this.setTextSymbol) {
                this.setTextSymbol(s[0]);
            }

            if (this.setBoxStyle) {
                var _style = this.getBoxStyle() || {};

                _style.symbol = s[1];
                this.setBoxStyle(_style);
            } else if (this.setBoxSymbol) {
                this.setBoxSymbol(s[1]);
            }

            return this;
        };

        _proto._parseSymbol = function _parseSymbol(symbol) {
            var t = {};
            var b = {};

            for (var p in symbol) {
                if (hasOwn(symbol, p)) {
                    if (p.indexOf('text') === 0) {
                        t[p] = symbol[p];
                    } else {
                        b[p] = symbol[p];
                    }
                }
            }

            return [t, b];
        };

        _proto._getTextSize = function _getTextSize(symbol) {
            return splitTextToRow(this._content, symbol)['size'];
        };

        _proto._getInternalSymbol = function _getInternalSymbol() {
            return this._symbol;
        };

        _proto._getDefaultTextSymbol = function _getDefaultTextSymbol() {
            return extend({}, defaultSymbol$1);
        };

        _proto._getDefaultBoxSymbol = function _getDefaultBoxSymbol() {
            return extend({}, defaultBoxSymbol);
        };

        _proto._getDefaultPadding = function _getDefaultPadding() {
            return [12, 8];
        };

        return TextMarker;
    }(Marker);

    var options$b = {
        'textStyle': {
            'wrap': true,
            'padding': [12, 8],
            'verticalAlignment': 'middle',
            'horizontalAlignment': 'middle'
        },
        'boxSymbol': null
    };

    var TextBox = function(_TextMarker) {
        _inheritsLoose(TextBox, _TextMarker);

        function TextBox(content, coordinates, width, height, options) {
            var _this;

            if (options === void 0) {
                options = {};
            }

            _this = _TextMarker.call(this, coordinates, options) || this;
            _this._content = escapeSpecialChars(content);
            _this._width = isNil(width) ? 100 : width;
            _this._height = isNil(height) ? 40 : height;

            if (options.boxSymbol) {
                _this.setBoxSymbol(options.boxSymbol);
            }

            if (options.textStyle) {
                _this.setTextStyle(options.textStyle);
            }

            _this._refresh();

            return _this;
        }

        var _proto = TextBox.prototype;

        _proto.getWidth = function getWidth() {
            return this._width;
        };

        _proto.setWidth = function setWidth(width) {
            this._width = width;

            this._refresh();

            return this;
        };

        _proto.getHeight = function getHeight() {
            return this._height;
        };

        _proto.setHeight = function setHeight(height) {
            this._height = height;

            this._refresh();

            return this;
        };

        _proto.getBoxSymbol = function getBoxSymbol() {
            return extend({}, this.options.boxSymbol);
        };

        _proto.setBoxSymbol = function setBoxSymbol(symbol) {
            this.options.boxSymbol = symbol ? extend({}, symbol) : symbol;

            if (this.getSymbol()) {
                this._refresh();
            }

            return this;
        };

        _proto.getTextStyle = function getTextStyle() {
            if (!this.options.textStyle) {
                return null;
            }

            return extend({}, this.options.textStyle);
        };

        _proto.setTextStyle = function setTextStyle(style) {
            this.options.textStyle = style ? extend({}, style) : style;

            if (this.getSymbol()) {
                this._refresh();
            }

            return this;
        };

        TextBox.fromJSON = function fromJSON(json) {
            var feature = json['feature'];
            var textBox = new TextBox(json['content'], feature['geometry']['coordinates'], json['width'], json['height'], json['options']);
            textBox.setProperties(feature['properties']);
            textBox.setId(feature['id']);

            if (json['symbol']) {
                textBox.setSymbol(json['symbol']);
            }

            return textBox;
        };

        _proto._toJSON = function _toJSON(options) {
            return {
                'feature': this.toGeoJSON(options),
                'width': this.getWidth(),
                'height': this.getHeight(),
                'subType': 'TextBox',
                'content': this._content
            };
        };

        _proto._refresh = function _refresh() {
            var textStyle = this.getTextStyle() || {},
                padding = textStyle['padding'] || [12, 8],
                maxWidth = this._width - 2 * padding[0],
                maxHeight = this._height - 2 * padding[1];
            var symbol = extend({}, textStyle.symbol || this._getDefaultTextSymbol(), this.options.boxSymbol || this._getDefaultBoxSymbol(), {
                'textName': this._content,
                'markerWidth': this._width,
                'markerHeight': this._height,
                'textHorizontalAlignment': 'middle',
                'textVerticalAlignment': 'middle',
                'textMaxWidth': maxWidth,
                'textMaxHeight': maxHeight
            });

            if (textStyle['wrap'] && !symbol['textWrapWidth']) {
                symbol['textWrapWidth'] = maxWidth;
            }

            var hAlign = textStyle['horizontalAlignment'];
            symbol['textDx'] = symbol['markerDx'] || 0;
            var offsetX = symbol['markerWidth'] / 2 - padding[0];

            if (hAlign === 'left') {
                symbol['textHorizontalAlignment'] = 'right';
                symbol['textDx'] = symbol['textDx'] - offsetX;
            } else if (hAlign === 'right') {
                symbol['textHorizontalAlignment'] = 'left';
                symbol['textDx'] = symbol['textDx'] + offsetX;
            }

            var vAlign = textStyle['verticalAlignment'];
            symbol['textDy'] = symbol['markerDy'] || 0;
            var offsetY = symbol['markerHeight'] / 2 - padding[1];

            if (vAlign === 'top') {
                symbol['textVerticalAlignment'] = 'bottom';
                symbol['textDy'] -= offsetY;
            } else if (vAlign === 'bottom') {
                symbol['textVerticalAlignment'] = 'top';
                symbol['textDy'] += offsetY;
            }

            this._refreshing = true;
            this.updateSymbol(symbol);
            delete this._refreshing;
        };

        return TextBox;
    }(TextMarker);

    TextBox.mergeOptions(options$b);
    TextBox.registerJSONType('TextBox');

    var options$c = {
        'boxStyle': null,
        textSymbol: null
    };

    var Label = function(_TextMarker) {
        _inheritsLoose(Label, _TextMarker);

        function Label(content, coordinates, options) {
            var _this;

            if (options === void 0) {
                options = {};
            }

            _this = _TextMarker.call(this, coordinates, options) || this;

            if (options.textSymbol) {
                _this.setTextSymbol(options.textSymbol);
            }

            if (options.boxStyle) {
                _this.setBoxStyle(options.boxStyle);
            }

            _this._content = escapeSpecialChars(content);

            _this._refresh();

            return _this;
        }

        var _proto = Label.prototype;

        _proto.getBoxStyle = function getBoxStyle() {
            if (!this.options.boxStyle) {
                return null;
            }

            return extend({}, this.options.boxStyle);
        };

        _proto.setBoxStyle = function setBoxStyle(style) {
            this.options.boxStyle = style ? extend({}, style) : style;

            this._refresh();

            return this;
        };

        _proto.getTextSymbol = function getTextSymbol() {
            return extend({}, this._getDefaultTextSymbol(), this.options.textSymbol);
        };

        _proto.setTextSymbol = function setTextSymbol(symbol) {
            this.options.textSymbol = symbol ? extend({}, symbol) : symbol;

            this._refresh();

            return this;
        };

        Label.fromJSON = function fromJSON(json) {
            var feature = json['feature'];
            var label = new Label(json['content'], feature['geometry']['coordinates'], json['options']);
            label.setProperties(feature['properties']);
            label.setId(feature['id']);

            if (json['symbol']) {
                label.setSymbol(json['symbol']);
            }

            return label;
        };

        _proto._canEdit = function _canEdit() {
            return false;
        };

        _proto._toJSON = function _toJSON(options) {
            return {
                'feature': this.toGeoJSON(options),
                'subType': 'Label',
                'content': this._content
            };
        };

        _proto._refresh = function _refresh() {
            var symbol = extend({}, this.getTextSymbol(), {
                'textName': this._content
            });
            var boxStyle = this.getBoxStyle();

            if (boxStyle) {
                extend(symbol, boxStyle.symbol);

                var sizes = this._getBoxSize(symbol),
                    textSize = sizes[1],
                    padding = boxStyle['padding'] || this._getDefaultPadding();

                var boxSize = sizes[0];
                symbol['markerWidth'] = boxSize['width'];
                symbol['markerHeight'] = boxSize['height'];

                var dx = symbol['textDx'] || 0,
                    dy = symbol['textDy'] || 0,
                    textAlignPoint = getAlignPoint(textSize, symbol['textHorizontalAlignment'], symbol['textVerticalAlignment'])._add(dx, dy);

                var hAlign = boxStyle['horizontalAlignment'] || 'middle';
                symbol['markerDx'] = textAlignPoint.x;

                if (hAlign === 'left') {
                    symbol['markerDx'] += symbol['markerWidth'] / 2 - padding[0];
                } else if (hAlign === 'right') {
                    symbol['markerDx'] -= symbol['markerWidth'] / 2 - textSize['width'] - padding[0];
                } else {
                    symbol['markerDx'] += textSize['width'] / 2;
                }

                var vAlign = boxStyle['verticalAlignment'] || 'middle';
                symbol['markerDy'] = textAlignPoint.y;

                if (vAlign === 'top') {
                    symbol['markerDy'] += symbol['markerHeight'] / 2 - padding[1];
                } else if (vAlign === 'bottom') {
                    symbol['markerDy'] -= symbol['markerHeight'] / 2 - textSize['height'] - padding[1];
                } else {
                    symbol['markerDy'] += textSize['height'] / 2;
                }
            }

            this._refreshing = true;
            this.updateSymbol(symbol);
            delete this._refreshing;
        };

        _proto._getBoxSize = function _getBoxSize(symbol) {
            if (!symbol['markerType']) {
                symbol['markerType'] = 'square';
            }

            var boxStyle = this.getBoxStyle();

            var size = this._getTextSize(symbol);

            var width, height;

            var padding = boxStyle['padding'] || this._getDefaultPadding();

            width = size['width'] + padding[0] * 2;
            height = size['height'] + padding[1] * 2;

            if (boxStyle['minWidth']) {
                if (!width || width < boxStyle['minWidth']) {
                    width = boxStyle['minWidth'];
                }
            }

            if (boxStyle['minHeight']) {
                if (!height || height < boxStyle['minHeight']) {
                    height = boxStyle['minHeight'];
                }
            }

            return [new Size(width, height), size];
        };

        return Label;
    }(TextMarker);

    Label.mergeOptions(options$c);
    Label.registerJSONType('Label');

    var Connectable = function Connectable(Base) {
        return function(_Base) {
            _inheritsLoose(_class, _Base);

            function _class() {
                return _Base.apply(this, arguments) || this;
            }

            _class._hasConnectors = function _hasConnectors(geometry) {
                return !isNil(geometry.__connectors) && geometry.__connectors.length > 0;
            };

            _class._getConnectors = function _getConnectors(geometry) {
                return geometry.__connectors;
            };

            var _proto = _class.prototype;

            _proto.getConnectSource = function getConnectSource() {
                return this._connSource;
            };

            _proto.setConnectSource = function setConnectSource(src) {
                var target = this._connTarget;
                this.onRemove();
                this._connSource = src;
                this._connTarget = target;
                this.onAdd();
                return this;
            };

            _proto.getConnectTarget = function getConnectTarget() {
                return this._connTarget;
            };

            _proto.setConnectTarget = function setConnectTarget(target) {
                var src = this._connSource;
                this.onRemove();
                this._connSource = src;
                this._connTarget = target;

                this._updateCoordinates();

                this._registerEvents();

                return this;
            };

            _proto._updateCoordinates = function _updateCoordinates() {
                var map = this.getMap();

                if (!map && this._connSource) {
                    map = this._connSource.getMap();
                }

                if (!map && this._connTarget) {
                    map = this._connTarget.getMap();
                }

                if (!map) {
                    return;
                }

                if (!this._connSource || !this._connTarget) {
                    return;
                }

                var srcPoints = this._connSource._getConnectPoints();

                var targetPoints = this._connTarget._getConnectPoints();

                var minDist = 0;
                var oldCoordinates = this.getCoordinates();
                var c1, c2;

                for (var i = 0, len = srcPoints.length; i < len; i++) {
                    var p1 = srcPoints[i];

                    for (var j = 0, length = targetPoints.length; j < length; j++) {
                        var p2 = targetPoints[j];
                        var dist = map.computeLength(p1, p2);

                        if (i === 0 && j === 0) {
                            c1 = p1;
                            c2 = p2;
                            minDist = dist;
                        } else if (dist < minDist) {
                            c1 = p1;
                            c2 = p2;
                        }
                    }
                }

                if (!isArrayHasData(oldCoordinates) || !oldCoordinates[0].equals(c1) || !oldCoordinates[1].equals(c2)) {
                    this.setCoordinates([c1, c2]);
                }
            };

            _proto.onAdd = function onAdd() {
                this._registerEvents();

                this._updateCoordinates();
            };

            _proto.onRemove = function onRemove() {
                if (this._connSource) {
                    if (this._connSource.__connectors) {
                        removeFromArray(this, this._connSource.__connectors);
                    }

                    this._connSource.off('dragging positionchange', this._updateCoordinates, this).off('remove', this.onRemove, this);

                    this._connSource.off('dragstart mousedown mouseover', this._showConnect, this);

                    this._connSource.off('dragend mouseup mouseout', this.hide, this);

                    this._connSource.off('show', this._showConnect, this).off('hide', this.hide, this);

                    delete this._connSource;
                }

                if (this._connTarget) {
                    removeFromArray(this, this._connTarget.__connectors);

                    this._connTarget.off('dragging positionchange', this._updateCoordinates, this).off('remove', this.onRemove, this);

                    this._connTarget.off('show', this._showConnect, this).off('hide', this.hide, this);

                    delete this._connTarget;
                }

                if (!(this._connSource instanceof Geometry) || !(this._connTarget instanceof Geometry)) {
                    var map = this.getMap();

                    if (map) {
                        map.off('movestart moving moveend zoomstart zooming zoomend rotate pitch fovchange spatialreferencechange', this._updateCoordinates, this);
                    }
                }
            };

            _proto._showConnect = function _showConnect() {
                if (!this._connSource || !this._connTarget) {
                    return;
                }

                if (this._connSource.isVisible() && this._connTarget.isVisible()) {
                    this._updateCoordinates();

                    this.show();
                }
            };

            _proto._registerEvents = function _registerEvents() {
                if (!this._connSource || !this._connTarget) {
                    return;
                }

                if (!this._connSource.__connectors) {
                    this._connSource.__connectors = [];
                }

                if (!this._connTarget.__connectors) {
                    this._connTarget.__connectors = [];
                }

                this._connSource.__connectors.push(this);

                this._connTarget.__connectors.push(this);

                this._connSource.on('dragging positionchange', this._updateCoordinates, this).on('remove', this.remove, this);

                this._connTarget.on('dragging positionchange', this._updateCoordinates, this).on('remove', this.remove, this);

                this._connSource.on('show', this._showConnect, this).on('hide', this.hide, this);

                this._connTarget.on('show', this._showConnect, this).on('hide', this.hide, this);

                var trigger = this.options['showOn'];
                this.hide();

                if (trigger === 'moving') {
                    this._connSource.on('dragstart', this._showConnect, this).on('dragend', this.hide, this);

                    this._connTarget.on('dragstart', this._showConnect, this).on('dragend', this.hide, this);
                } else if (trigger === 'click') {
                    this._connSource.on('mousedown', this._showConnect, this).on('mouseup', this.hide, this);

                    this._connTarget.on('mousedown', this._showConnect, this).on('mouseup', this.hide, this);
                } else if (trigger === 'mouseover') {
                    this._connSource.on('mouseover', this._showConnect, this).on('mouseout', this.hide, this);

                    this._connTarget.on('mouseover', this._showConnect, this).on('mouseout', this.hide, this);
                } else {
                    this._showConnect();
                }

                if (!(this._connSource instanceof Geometry) || !(this._connTarget instanceof Geometry)) {
                    var map = this.getMap();

                    if (map) {
                        map.on('movestart moving moveend zoomstart zooming zoomend rotate pitch fovchange spatialreferencechange', this._updateCoordinates, this);
                    }
                }
            };

            return _class;
        }(Base);
    };

    var options$d = {
        showOn: 'always'
    };

    var ConnectorLine = function(_Connectable) {
        _inheritsLoose(ConnectorLine, _Connectable);

        function ConnectorLine(src, target, options) {
            var _this;

            _this = _Connectable.call(this, null, options) || this;

            if (arguments.length === 1) {
                options = src;
                src = null;
                target = null;
            }

            _this._connSource = src;
            _this._connTarget = target;
            return _this;
        }

        return ConnectorLine;
    }(Connectable(LineString));

    ConnectorLine.mergeOptions(options$d);
    ConnectorLine.registerJSONType('ConnectorLine');

    var ArcConnectorLine = function(_Connectable2) {
        _inheritsLoose(ArcConnectorLine, _Connectable2);

        function ArcConnectorLine(src, target, options) {
            var _this2;

            _this2 = _Connectable2.call(this, null, options) || this;

            if (arguments.length === 1) {
                options = src;
                src = null;
                target = null;
            }

            _this2._connSource = src;
            _this2._connTarget = target;
            return _this2;
        }

        return ArcConnectorLine;
    }(Connectable(ArcCurve));

    ArcConnectorLine.mergeOptions(options$d);
    ArcConnectorLine.registerJSONType('ArcConnectorLine');

    var options$e = {
        'drawImmediate': false
    };

    var OverlayLayer = function(_Layer) {
        _inheritsLoose(OverlayLayer, _Layer);

        function OverlayLayer(id, geometries, options) {
            var _this;

            if (geometries && !(geometries instanceof Geometry) && !Array.isArray(geometries) && GEOJSON_TYPES.indexOf(geometries.type) < 0) {
                options = geometries;
                geometries = null;
            }

            _this = _Layer.call(this, id, options) || this;
            _this._maxZIndex = 0;
            _this._minZIndex = 0;

            _this._initCache();

            if (geometries) {
                _this.addGeometry(geometries);
            }

            var style = _this.options['style'];

            if (style) {
                _this.setStyle(style);
            }

            return _this;
        }

        var _proto = OverlayLayer.prototype;

        _proto.getGeometryById = function getGeometryById(id) {
            if (isNil(id) || id === '') {
                return null;
            }

            if (!this._geoMap[id]) {
                return null;
            }

            return this._geoMap[id];
        };

        _proto.getGeometries = function getGeometries(filter, context) {
            if (!filter) {
                return this._geoList.slice(0);
            }

            var result = [];
            var geometry, filtered;

            for (var i = 0, l = this._geoList.length; i < l; i++) {
                geometry = this._geoList[i];

                if (context) {
                    filtered = filter.call(context, geometry);
                } else {
                    filtered = filter(geometry);
                }

                if (filtered) {
                    result.push(geometry);
                }
            }

            return result;
        };

        _proto.getFirstGeometry = function getFirstGeometry() {
            if (!this._geoList.length) {
                return null;
            }

            return this._geoList[0];
        };

        _proto.getLastGeometry = function getLastGeometry() {
            var len = this._geoList.length;

            if (len === 0) {
                return null;
            }

            return this._geoList[len - 1];
        };

        _proto.getCount = function getCount() {
            return this._geoList.length;
        };

        _proto.getExtent = function getExtent() {
            if (this.getCount() === 0) {
                return null;
            }

            var extent = new Extent(this.getProjection());
            this.forEach(function(g) {
                extent._combine(g.getExtent());
            });
            return extent;
        };

        _proto.forEach = function forEach(fn, context) {
            var copyOnWrite = this._geoList.slice(0);

            for (var i = 0, l = copyOnWrite.length; i < l; i++) {
                if (!context) {
                    fn(copyOnWrite[i], i);
                } else {
                    fn.call(context, copyOnWrite[i], i);
                }
            }

            return this;
        };

        _proto.filter = function filter(fn, context) {
            var selected = [];
            var isFn = isFunction(fn);
            var filter = isFn ? fn : createFilter(fn);
            this.forEach(function(geometry) {
                var g = isFn ? geometry : getFilterFeature(geometry);

                if (context ? filter.call(context, g) : filter(g)) {
                    selected.push(geometry);
                }
            }, this);
            return selected;
        };

        _proto.isEmpty = function isEmpty$$1() {
            return !this._geoList.length;
        };

        _proto.addGeometry = function addGeometry(geometries, fitView) {
            if (!geometries) {
                return this;
            }

            if (geometries.type === 'FeatureCollection') {
                return this.addGeometry(GeoJSON.toGeometry(geometries), fitView);
            } else if (!Array.isArray(geometries)) {
                var count = arguments.length;
                var last = arguments[count - 1];
                geometries = Array.prototype.slice.call(arguments, 0, count - 1);
                fitView = last;

                if (last && isObject(last) && ('type' in last || last instanceof Geometry)) {
                    geometries.push(last);
                    fitView = false;
                }

                return this.addGeometry(geometries, fitView);
            } else if (geometries.length === 0) {
                return this;
            }

            this._initCache();

            var extent;

            if (fitView) {
                extent = new Extent();
            }

            this._toSort = this._maxZIndex > 0;
            var geos = [];

            for (var i = 0, l = geometries.length; i < l; i++) {
                var geo = geometries[i];

                if (!geo) {
                    throw new Error('Invalid geometry to add to layer(' + this.getId() + ') at index:' + i);
                }

                if (!(geo instanceof Geometry)) {
                    geo = Geometry.fromJSON(geo);

                    if (Array.isArray(geo)) {
                        for (var ii = 0, ll = geo.length; ii < ll; ii++) {
                            this._add(geo[ii], extent, i);

                            geos.push(geo[ii]);
                        }
                    }
                }

                if (!Array.isArray(geo)) {
                    this._add(geo, extent, i);

                    geos.push(geo);
                }
            }

            var map = this.getMap();

            if (map) {
                this._getRenderer().onGeometryAdd(geos);

                if (extent && !isNil(extent.xmin)) {
                    var center = extent.getCenter();
                    var z = map.getFitZoom(extent);

                    if (isObject(fitView)) {
                        var step = isFunction(fitView.step) ? fitView.step : function() {
                            return undefined;
                        };
                        map.animateTo({
                            center: center,
                            zoom: z
                        }, extend({
                            duration: map.options.zoomAnimationDuration,
                            easing: 'out'
                        }, fitView), step);
                    } else if (fitView === true) {
                        map.setCenterAndZoom(center, z);
                    }
                }
            }

            this.fire('addgeo', {
                'geometries': geometries
            });
            return this;
        };

        _proto.getGeoMinZIndex = function getGeoMinZIndex() {
            return this._minZIndex;
        };

        _proto.getGeoMaxZIndex = function getGeoMaxZIndex() {
            return this._maxZIndex;
        };

        _proto._add = function _add(geo, extent, i) {
            if (!this._toSort) {
                this._toSort = geo.getZIndex() !== 0;
            }

            this._updateZIndex(geo.getZIndex());

            var geoId = geo.getId();

            if (!isNil(geoId)) {
                if (!isNil(this._geoMap[geoId])) {
                    throw new Error('Duplicate geometry id in layer(' + this.getId() + '):' + geoId + ', at index:' + i);
                }

                this._geoMap[geoId] = geo;
            }

            var internalId = UID();

            geo._setInternalId(internalId);

            this._geoList.push(geo);

            this.onAddGeometry(geo);

            geo._bindLayer(this);

            if (geo.onAdd) {
                geo.onAdd();
            }

            if (extent) {
                extent._combine(geo.getExtent());
            }

            geo._fireEvent('add', {
                'layer': this
            });

            if (this._cookedStyles) {
                this._styleGeometry(geo);
            }
        };

        _proto.removeGeometry = function removeGeometry(geometries) {
            if (!Array.isArray(geometries)) {
                return this.removeGeometry([geometries]);
            }

            for (var i = geometries.length - 1; i >= 0; i--) {
                if (!(geometries[i] instanceof Geometry)) {
                    geometries[i] = this.getGeometryById(geometries[i]);
                }

                if (!geometries[i] || this !== geometries[i].getLayer()) continue;
                geometries[i].remove();
            }

            this.fire('removegeo', {
                'geometries': geometries
            });
            return this;
        };

        _proto.clear = function clear() {
            this._clearing = true;
            this.forEach(function(geo) {
                geo.remove();
            });
            this._geoMap = {};
            var old = this._geoList;
            this._geoList = [];

            if (this._getRenderer()) {
                this._getRenderer().onGeometryRemove(old);
            }

            this._clearing = false;
            this.fire('clear');
            return this;
        };

        _proto.onRemoveGeometry = function onRemoveGeometry(geometry) {
            if (!geometry || this._clearing) {
                return;
            }

            if (this !== geometry.getLayer()) {
                return;
            }

            var internalId = geometry._getInternalId();

            if (isNil(internalId)) {
                return;
            }

            var geoId = geometry.getId();

            if (!isNil(geoId)) {
                delete this._geoMap[geoId];
            }

            var idx = this._findInList(geometry);

            if (idx >= 0) {
                this._geoList.splice(idx, 1);
            }

            if (this._getRenderer()) {
                this._getRenderer().onGeometryRemove([geometry]);
            }
        };

        _proto.getStyle = function getStyle() {
            if (!this.options['style']) {
                return null;
            }

            return this.options['style'];
        };

        _proto.setStyle = function setStyle(style) {
            this.options.style = style;
            style = parseStyleRootPath(style);
            this._cookedStyles = compileStyle(style);
            this.forEach(function(geometry) {
                this._styleGeometry(geometry);
            }, this);
            this.fire('setstyle', {
                'style': style
            });
            return this;
        };

        _proto._styleGeometry = function _styleGeometry(geometry) {
            if (!this._cookedStyles) {
                return false;
            }

            var g = getFilterFeature(geometry);

            for (var i = 0, len = this._cookedStyles.length; i < len; i++) {
                if (this._cookedStyles[i]['filter'](g) === true) {
                    geometry._setExternSymbol(this._cookedStyles[i]['symbol']);

                    return true;
                }
            }

            return false;
        };

        _proto.removeStyle = function removeStyle() {
            if (!this.options.style) {
                return this;
            }

            delete this.options.style;
            delete this._cookedStyles;
            this.forEach(function(geometry) {
                geometry._setExternSymbol(null);
            }, this);
            this.fire('removestyle');
            return this;
        };

        _proto.onAddGeometry = function onAddGeometry(geo) {
            var style = this.getStyle();

            if (style) {
                this._styleGeometry(geo);
            }
        };

        _proto.hide = function hide() {
            for (var i = 0, l = this._geoList.length; i < l; i++) {
                this._geoList[i].onHide();
            }

            return Layer.prototype.hide.call(this);
        };

        _proto._initCache = function _initCache() {
            if (!this._geoList) {
                this._geoList = [];
                this._geoMap = {};
            }
        };

        _proto._updateZIndex = function _updateZIndex() {
            for (var _len = arguments.length, zIndex = new Array(_len), _key = 0; _key < _len; _key++) {
                zIndex[_key] = arguments[_key];
            }

            this._maxZIndex = Math.max(this._maxZIndex, Math.max.apply(Math, zIndex));
            this._minZIndex = Math.min(this._minZIndex, Math.min.apply(Math, zIndex));
        };

        _proto._sortGeometries = function _sortGeometries() {
            var _this2 = this;

            if (!this._toSort) {
                return;
            }

            this._maxZIndex = 0;
            this._minZIndex = 0;

            this._geoList.sort(function(a, b) {
                _this2._updateZIndex(a.getZIndex(), b.getZIndex());

                return _this2._compare(a, b);
            });

            this._toSort = false;
        };

        _proto._compare = function _compare(a, b) {
            if (a.getZIndex() === b.getZIndex()) {
                return a._getInternalId() - b._getInternalId();
            }

            return a.getZIndex() - b.getZIndex();
        };

        _proto._findInList = function _findInList(geo) {
            var len = this._geoList.length;

            if (len === 0) {
                return -1;
            }

            this._sortGeometries();

            var low = 0,
                high = len - 1,
                middle;

            while (low <= high) {
                middle = Math.floor((low + high) / 2);

                if (this._geoList[middle] === geo) {
                    return middle;
                } else if (this._compare(this._geoList[middle], geo) > 0) {
                    high = middle - 1;
                } else {
                    low = middle + 1;
                }
            }

            return -1;
        };

        _proto._onGeometryEvent = function _onGeometryEvent(param) {
            if (!param || !param['target']) {
                return;
            }

            var type = param['type'];

            if (type === 'idchange') {
                this._onGeometryIdChange(param);
            } else if (type === 'zindexchange') {
                this._onGeometryZIndexChange(param);
            } else if (type === 'positionchange') {
                this._onGeometryPositionChange(param);
            } else if (type === 'shapechange') {
                this._onGeometryShapeChange(param);
            } else if (type === 'symbolchange') {
                this._onGeometrySymbolChange(param);
            } else if (type === 'show') {
                this._onGeometryShow(param);
            } else if (type === 'hide') {
                this._onGeometryHide(param);
            } else if (type === 'propertieschange') {
                this._onGeometryPropertiesChange(param);
            }
        };

        _proto._onGeometryIdChange = function _onGeometryIdChange(param) {
            if (param['new'] === param['old']) {
                if (this._geoMap[param['old']] && this._geoMap[param['old']] === param['target']) {
                    return;
                }
            }

            if (!isNil(param['new'])) {
                if (this._geoMap[param['new']]) {
                    throw new Error('Duplicate geometry id in layer(' + this.getId() + '):' + param['new']);
                }

                this._geoMap[param['new']] = param['target'];
            }

            if (!isNil(param['old']) && param['new'] !== param['old']) {
                delete this._geoMap[param['old']];
            }
        };

        _proto._onGeometryZIndexChange = function _onGeometryZIndexChange(param) {
            if (param['old'] !== param['new']) {
                this._updateZIndex(param['new']);

                this._toSort = true;

                if (this._getRenderer()) {
                    this._getRenderer().onGeometryZIndexChange(param);
                }
            }
        };

        _proto._onGeometryPositionChange = function _onGeometryPositionChange(param) {
            if (this._getRenderer()) {
                this._getRenderer().onGeometryPositionChange(param);
            }
        };

        _proto._onGeometryShapeChange = function _onGeometryShapeChange(param) {
            if (this._getRenderer()) {
                this._getRenderer().onGeometryShapeChange(param);
            }
        };

        _proto._onGeometrySymbolChange = function _onGeometrySymbolChange(param) {
            if (this._getRenderer()) {
                this._getRenderer().onGeometrySymbolChange(param);
            }
        };

        _proto._onGeometryShow = function _onGeometryShow(param) {
            if (this._getRenderer()) {
                this._getRenderer().onGeometryShow(param);
            }
        };

        _proto._onGeometryHide = function _onGeometryHide(param) {
            if (this._getRenderer()) {
                this._getRenderer().onGeometryHide(param);
            }
        };

        _proto._onGeometryPropertiesChange = function _onGeometryPropertiesChange(param) {
            if (this._getRenderer()) {
                this._getRenderer().onGeometryPropertiesChange(param);
            }
        };

        return OverlayLayer;
    }(Layer);

    OverlayLayer.mergeOptions(options$e);

    var TEMP_EXTENT$3 = new PointExtent();
    var options$f = {
        'debug': false,
        'enableSimplify': true,
        'geometryEvents': true,
        'defaultIconSize': [20, 20],
        'cacheVectorOnCanvas': true,
        'cacheSvgOnCanvas': Browser$1.gecko,
        'enableAltitude': false,
        'altitudeProperty': 'altitude',
        'drawAltitude': false,
        'altitude': 0
    };

    var VectorLayer = function(_OverlayLayer) {
        _inheritsLoose(VectorLayer, _OverlayLayer);

        function VectorLayer(id, geometries, options) {
            return _OverlayLayer.call(this, id, geometries, options) || this;
        }

        var _proto = VectorLayer.prototype;

        _proto.onConfig = function onConfig(conf) {
            _OverlayLayer.prototype.onConfig.call(this, conf);

            if (conf['enableAltitude'] || conf['drawAltitude'] || conf['altitudeProperty']) {
                var renderer = this.getRenderer();

                if (renderer && renderer.setToRedraw) {
                    renderer.setToRedraw();
                }
            }
        };

        _proto.identify = function identify(coordinate, options) {
            if (options === void 0) {
                options = {};
            }

            var renderer = this.getRenderer();

            if (options['onlyVisible'] && renderer && renderer.identify) {
                return renderer.identify(coordinate, options);
            }

            if (!(coordinate instanceof Coordinate)) {
                coordinate = new Coordinate(coordinate);
            }

            return this._hitGeos(this._geoList, coordinate, options);
        };

        _proto._hitGeos = function _hitGeos(geometries, coordinate, options) {
            if (options === void 0) {
                options = {};
            }

            var filter = options['filter'],
                tolerance = options['tolerance'],
                hits = [];
            var map = this.getMap();
            var point = map.coordToPoint(coordinate);

            var cp = map._pointToContainerPoint(point, undefined, 0, point);

            for (var i = geometries.length - 1; i >= 0; i--) {
                var geo = geometries[i];

                if (!geo || !geo.isVisible() || !geo._getPainter() || !geo.options['interactive']) {
                    continue;
                }

                if (!(geo instanceof LineString) || !geo._getArrowStyle() && !(geo instanceof Curve)) {
                    var extent = geo.getContainerExtent(TEMP_EXTENT$3);

                    if (tolerance) {
                        extent = extent._expand(tolerance);
                    }

                    if (!extent || !extent.contains(cp)) {
                        continue;
                    }
                }

                if (geo._containsPoint(cp, tolerance) && (!filter || filter(geo))) {
                    hits.push(geo);

                    if (options['count']) {
                        if (hits.length >= options['count']) {
                            break;
                        }
                    }
                }
            }

            return hits;
        };

        _proto.getAltitude = function getAltitude() {
            return this.options['altitude'] || 0;
        };

        _proto.toJSON = function toJSON(options) {
            if (!options) {
                options = {};
            }

            var profile = {
                'type': this.getJSONType(),
                'id': this.getId(),
                'options': this.config()
            };

            if (isNil(options['geometries']) || options['geometries']) {
                var clipExtent;

                if (options['clipExtent']) {
                    var map = this.getMap();
                    var projection = map ? map.getProjection() : null;
                    clipExtent = new Extent(options['clipExtent'], projection);
                }

                var geoJSONs = [];
                var geometries = this.getGeometries();

                for (var i = 0, len = geometries.length; i < len; i++) {
                    var geo = geometries[i];
                    var geoExt = geo.getExtent();

                    if (!geoExt || clipExtent && !clipExtent.intersects(geoExt)) {
                        continue;
                    }

                    var json = geo.toJSON(options['geometries']);
                    geoJSONs.push(json);
                }

                profile['geometries'] = geoJSONs;
            }

            return profile;
        };

        VectorLayer.fromJSON = function fromJSON(json) {
            if (!json || json['type'] !== 'VectorLayer') {
                return null;
            }

            var layer = new VectorLayer(json['id'], json['options']);
            var geoJSONs = json['geometries'];
            var geometries = [];

            for (var i = 0; i < geoJSONs.length; i++) {
                var geo = Geometry.fromJSON(geoJSONs[i]);

                if (geo) {
                    geometries.push(geo);
                }
            }

            layer.addGeometry(geometries);
            return layer;
        };

        VectorLayer.getPainterClass = function getPainterClass() {
            return Painter;
        };

        VectorLayer.getCollectionPainterClass = function getCollectionPainterClass() {
            return CollectionPainter;
        };

        return VectorLayer;
    }(OverlayLayer);

    VectorLayer.mergeOptions(options$f);
    VectorLayer.registerJSONType('VectorLayer');

    var key = '_map_tool';

    var MapTool = function(_Eventable) {
        _inheritsLoose(MapTool, _Eventable);

        function MapTool() {
            return _Eventable.apply(this, arguments) || this;
        }

        var _proto = MapTool.prototype;

        _proto.addTo = function addTo(map) {
            if (!map) {
                return this;
            }

            this._map = map;

            if (map[key]) {
                map[key].disable();
            }

            if (this.onAdd) {
                this.onAdd();
            }

            this.enable();
            map[key] = this;

            this._fireEvent('add');

            return this;
        };

        _proto.getMap = function getMap() {
            return this._map;
        };

        _proto.enable = function enable() {
            var map = this._map;

            if (!map || this._enabled) {
                return this;
            }

            this._enabled = true;

            this._switchEvents('off');

            this._registerEvents();

            if (this.onEnable) {
                this.onEnable();
            }

            this._fireEvent('enable');

            return this;
        };

        _proto.disable = function disable() {
            if (!this._enabled || !this._map) {
                return this;
            }

            this._enabled = false;

            this._switchEvents('off');

            if (this.onDisable) {
                this.onDisable();
            }

            this._fireEvent('disable');

            return this;
        };

        _proto.isEnabled = function isEnabled() {
            if (!this._enabled) {
                return false;
            }

            return true;
        };

        _proto.remove = function remove() {
            if (!this._map) {
                return this;
            }

            this.disable();

            if (this._map) {
                delete this._map[key];
                delete this._map;
            }

            this._fireEvent('remove');

            return this;
        };

        _proto._registerEvents = function _registerEvents() {
            this._switchEvents('on');
        };

        _proto._switchEvents = function _switchEvents(to) {
            var events = this.getEvents();

            if (events) {
                this._map[to](events, this);
            }
        };

        _proto._fireEvent = function _fireEvent(eventName, param) {
            if (!param) {
                param = {};
            }

            this.fire(eventName, param);
        };

        return MapTool;
    }(Eventable(Class));

    var options$g = {
        'symbol': {
            'lineColor': '#000',
            'lineWidth': 2,
            'lineOpacity': 1,
            'polygonFill': '#fff',
            'polygonOpacity': 0.3
        },
        'doubleClickZoom': false,
        'mode': null,
        'once': false,
        'autoPanAtEdge': false,
        'ignoreMouseleave': true
    };
    var registeredMode = {};

    var DrawTool = function(_MapTool) {
        _inheritsLoose(DrawTool, _MapTool);

        DrawTool.registerMode = function registerMode(name, modeAction) {
            registeredMode[name.toLowerCase()] = modeAction;
        };

        DrawTool.getRegisterMode = function getRegisterMode(name) {
            return registeredMode[name.toLowerCase()];
        };

        function DrawTool(options) {
            var _this;

            _this = _MapTool.call(this, options) || this;

            _this._checkMode();

            _this._events = {
                'click': _this._clickHandler,
                'mousemove': _this._mouseMoveHandler,
                'dblclick': _this._doubleClickHandler,
                'mousedown': _this._mouseDownHandler,
                'mouseup': _this._mouseUpHandler
            };
            return _this;
        }

        var _proto = DrawTool.prototype;

        _proto.getMode = function getMode() {
            if (this.options['mode']) {
                return this.options['mode'].toLowerCase();
            }

            return null;
        };

        _proto.setMode = function setMode(mode) {
            if (this._geometry) {
                this._geometry.remove();

                delete this._geometry;
            }

            this._clearStage();

            this._switchEvents('off');

            this.options['mode'] = mode;

            this._checkMode();

            if (this.isEnabled()) {
                this._switchEvents('on');

                this._restoreMapCfg();

                this._saveMapCfg();
            }

            return this;
        };

        _proto.getSymbol = function getSymbol() {
            var symbol = this.options['symbol'];

            if (symbol) {
                return extendSymbol(symbol);
            } else {
                return extendSymbol(this.options['symbol']);
            }
        };

        _proto.setSymbol = function setSymbol(symbol) {
            if (!symbol) {
                return this;
            }

            this.options['symbol'] = symbol;

            if (this._geometry) {
                this._geometry.setSymbol(symbol);
            }

            return this;
        };

        _proto.getCurrentGeometry = function getCurrentGeometry() {
            return this._geometry;
        };

        _proto.onAdd = function onAdd() {
            this._checkMode();
        };

        _proto.onEnable = function onEnable() {
            this._saveMapCfg();

            this._drawToolLayer = this._getDrawLayer();

            this._clearStage();

            this._loadResources();

            if (this.options['autoPanAtEdge']) {
                var map = this.getMap();
                this._mapAutoPanAtEdge = map.options['autoPanAtEdge'];

                if (!this._mapAutoPanAtEdge) {
                    map.config({
                        autoPanAtEdge: true
                    });
                }
            }

            return this;
        };

        _proto.onDisable = function onDisable() {
            var map = this.getMap();

            this._restoreMapCfg();

            this.endDraw();

            if (this._map) {
                map.removeLayer(this._getDrawLayer());

                if (this.options['autoPanAtEdge']) {
                    if (!this._mapAutoPanAtEdge) {
                        map.config({
                            autoPanAtEdge: false
                        });
                    }
                }
            }

            return this;
        };

        _proto.undo = function undo() {
            var registerMode = this._getRegisterMode();

            var action = registerMode.action;

            if (!this._shouldRecordHistory(action) || !this._historyPointer) {
                return this;
            }

            var coords = this._clickCoords.slice(0, --this._historyPointer);

            registerMode.update(this.getMap().getProjection(), coords, this._geometry);
            return this;
        };

        _proto.redo = function redo() {
            var registerMode = this._getRegisterMode();

            var action = registerMode.action;

            if (!this._shouldRecordHistory(action) || isNil(this._historyPointer) || this._historyPointer === this._clickCoords.length) {
                return this;
            }

            var coords = this._clickCoords.slice(0, ++this._historyPointer);

            registerMode.update(this.getMap().getProjection(), coords, this._geometry);
            return this;
        };

        _proto._shouldRecordHistory = function _shouldRecordHistory(actions) {
            return Array.isArray(actions) && actions[0] === 'click' && actions[1] === 'mousemove' && actions[2] === 'dblclick';
        };

        _proto._checkMode = function _checkMode() {
            this._getRegisterMode();
        };

        _proto._saveMapCfg = function _saveMapCfg() {
            var map = this.getMap();
            this._mapDoubleClickZoom = map.options['doubleClickZoom'];
            map.config({
                'doubleClickZoom': this.options['doubleClickZoom']
            });

            var actions = this._getRegisterMode()['action'];

            if (actions.indexOf('mousedown') > -1) {
                var _map = this.getMap();

                this._mapDraggable = _map.options['draggable'];

                _map.config({
                    'draggable': false
                });
            }
        };

        _proto._restoreMapCfg = function _restoreMapCfg() {
            var map = this.getMap();
            map.config({
                'doubleClickZoom': this._mapDoubleClickZoom
            });

            if (!isNil(this._mapDraggable)) {
                map.config('draggable', this._mapDraggable);
            }

            delete this._mapDraggable;
            delete this._mapDoubleClickZoom;
        };

        _proto._loadResources = function _loadResources() {
            var symbol = this.getSymbol();
            var resources = getExternalResources(symbol);

            if (resources.length > 0) {
                this._drawToolLayer._getRenderer().loadResources(resources);
            }
        };

        _proto._getProjection = function _getProjection() {
            return this._map.getProjection();
        };

        _proto._getRegisterMode = function _getRegisterMode() {
            var mode = this.getMode();
            var registerMode = DrawTool.getRegisterMode(mode);

            if (!registerMode) {
                throw new Error(mode + ' is not a valid mode of DrawTool.');
            }

            return registerMode;
        };

        _proto.getEvents = function getEvents() {
            var action = this._getRegisterMode()['action'];

            var _events = {};

            if (Array.isArray(action)) {
                for (var i = 0; i < action.length; i++) {
                    _events[action[i]] = this._events[action[i]];
                }

                return _events;
            }

            return null;
        };

        _proto._mouseDownHandler = function _mouseDownHandler(event) {
            this._createGeometry(event);
        };

        _proto._mouseUpHandler = function _mouseUpHandler(event) {
            this.endDraw(event);
        };

        _proto._clickHandler = function _clickHandler(event) {
            var registerMode = this._getRegisterMode();

            if (!this._geometry) {
                this._createGeometry(event);
            } else {
                var prjCoord = this.getMap()._pointToPrj(event['point2d']);

                if (!isNil(this._historyPointer)) {
                    this._clickCoords = this._clickCoords.slice(0, this._historyPointer);
                }

                this._clickCoords.push(prjCoord);

                this._historyPointer = this._clickCoords.length;
                event.drawTool = this;
                registerMode['update'](this.getMap().getProjection(), this._clickCoords, this._geometry, event);

                this._fireEvent('drawvertex', event);

                if (registerMode['clickLimit'] && registerMode['clickLimit'] === this._historyPointer) {
                    this.endDraw(event);
                }
            }
        };

        _proto._createGeometry = function _createGeometry(event) {
            var mode = this.getMode();

            var registerMode = this._getRegisterMode();

            var prjCoord = this.getMap()._pointToPrj(event['point2d']);

            var symbol = this.getSymbol();

            if (!this._geometry) {
                this._clickCoords = [prjCoord];
                event.drawTool = this;
                this._geometry = registerMode['create'](this.getMap().getProjection(), this._clickCoords, event);

                if (symbol && mode !== 'point') {
                    this._geometry.setSymbol(symbol);
                } else if (this.options.hasOwnProperty('symbol')) {
                    this._geometry.setSymbol(this.options['symbol']);
                }

                this._addGeometryToStage(this._geometry);

                this._fireEvent('drawstart', event);
            }

            if (mode === 'point') {
                this.endDraw(event);
            }
        };

        _proto._mouseMoveHandler = function _mouseMoveHandler(event) {
            var map = this.getMap();

            if (!this._geometry || !map || map.isInteracting()) {
                return;
            }

            var containerPoint = this._getMouseContainerPoint(event);

            if (!this._isValidContainerPoint(containerPoint)) {
                return;
            }

            var prjCoord = this.getMap()._pointToPrj(event['point2d']);

            var projection = map.getProjection();
            event.drawTool = this;

            var registerMode = this._getRegisterMode();

            if (this._shouldRecordHistory(registerMode.action)) {
                var path = this._clickCoords.slice(0, this._historyPointer);

                if (path && path.length > 0 && prjCoord.equals(path[path.length - 1])) {
                    return;
                }

                registerMode['update'](projection, path.concat([prjCoord]), this._geometry, event);
            } else {
                registerMode['update'](projection, prjCoord, this._geometry, event);
            }

            this._fireEvent('mousemove', event);
        };

        _proto._doubleClickHandler = function _doubleClickHandler(event) {
            if (!this._geometry) {
                return;
            }

            var containerPoint = this._getMouseContainerPoint(event);

            if (!this._isValidContainerPoint(containerPoint)) {
                return;
            }

            var registerMode = this._getRegisterMode();

            var clickCoords = this._clickCoords;

            if (clickCoords.length < 2) {
                return;
            }

            var projection = this.getMap().getProjection();
            var path = [clickCoords[0]];

            for (var i = 1, len = clickCoords.length; i < len; i++) {
                if (clickCoords[i].x !== clickCoords[i - 1].x || clickCoords[i].y !== clickCoords[i - 1].y) {
                    path.push(clickCoords[i]);
                }
            }

            if (path.length < 2 || this._geometry && this._geometry instanceof Polygon && path.length < 3) {
                return;
            }

            event.drawTool = this;
            registerMode['update'](projection, path, this._geometry, event);
            this.endDraw(event);
        };

        _proto._addGeometryToStage = function _addGeometryToStage(geometry) {
            var drawLayer = this._getDrawLayer();

            drawLayer.addGeometry(geometry);
        };

        _proto.endDraw = function endDraw(param) {
            if (!this._geometry || this._ending) {
                return this;
            }

            this._ending = true;
            var geometry = this._geometry;

            this._clearStage();

            param = param || {};
            this._geometry = geometry;

            this._fireEvent('drawend', param);

            delete this._geometry;

            if (this.options['once']) {
                this.disable();
            }

            delete this._ending;
            delete this._historyPointer;
            return this;
        };

        _proto._clearStage = function _clearStage() {
            this._getDrawLayer().clear();

            delete this._geometry;
            delete this._clickCoords;
        };

        _proto._getMouseContainerPoint = function _getMouseContainerPoint(event) {
            var action = this._getRegisterMode()['action'];

            if (action === 'mousedown') {
                stopPropagation(event['domEvent']);
            }

            return event['containerPoint'];
        };

        _proto._isValidContainerPoint = function _isValidContainerPoint(containerPoint) {
            var mapSize = this._map.getSize();

            var w = mapSize['width'],
                h = mapSize['height'];

            if (containerPoint.x < 0 || containerPoint.y < 0) {
                return false;
            } else if (containerPoint.x > w || containerPoint.y > h) {
                return false;
            }

            return true;
        };

        _proto._getDrawLayer = function _getDrawLayer() {
            var drawLayerId = INTERNAL_LAYER_PREFIX + 'drawtool';

            var drawToolLayer = this._map.getLayer(drawLayerId);

            if (!drawToolLayer) {
                drawToolLayer = new VectorLayer(drawLayerId, {
                    'enableSimplify': false
                });

                this._map.addLayer(drawToolLayer);
            }

            return drawToolLayer;
        };

        _proto._fireEvent = function _fireEvent(eventName, param) {
            if (!param) {
                param = {};
            }

            if (this._geometry) {
                param['geometry'] = this._getRegisterMode()['generate'](this._geometry, {
                    drawTool: this
                });
            }

            MapTool.prototype._fireEvent.call(this, eventName, param);
        };

        return DrawTool;
    }(MapTool);

    DrawTool.mergeOptions(options$g);

    var MapBoxZoomHander = function(_Handler) {
        _inheritsLoose(MapBoxZoomHander, _Handler);

        function MapBoxZoomHander(target) {
            var _this;

            _this = _Handler.call(this, target) || this;
            _this.drawTool = new DrawTool({
                'mode': 'boxZoom',
                'ignoreMouseleave': false
            });
            return _this;
        }

        var _proto = MapBoxZoomHander.prototype;

        _proto.addHooks = function addHooks() {
            this.target.on('_mousedown', this._onMouseDown, this);
        };

        _proto.removeHooks = function removeHooks() {
            this.target.off('_mousedown', this._onMouseDown, this);

            if (this.drawTool.isEnabled()) {
                this.drawTool.remove();
            }
        };

        _proto._onMouseDown = function _onMouseDown(param) {
            if (!this.target.options['boxZoom']) {
                return;
            }

            if (param.domEvent.shiftKey) {
                this.drawTool.setSymbol(this.target.options['boxZoomSymbol']).on('drawend', this._boxZoom, this).addTo(this.target);
            }
        };

        _proto._boxZoom = function _boxZoom(param) {
            var map = this.target;
            this.drawTool.remove();
            var geometry = param.geometry,
                center = geometry.getCenter(),
                symbol = geometry.getSymbol(),
                w = symbol.markerWidth,
                h = symbol.markerHeight;
            var extent = new Extent(center, map.locateByPoint(center, w, h), map.getProjection());
            var zoom = map.getFitZoom(extent);

            map._animateTo({
                center: extent.getCenter(),
                zoom: zoom
            });
        };

        return MapBoxZoomHander;
    }(Handler$1);

    Map$1.mergeOptions({
        'boxZoom': true,
        'boxZoomSymbol': {
            'markerType': 'rectangle',
            'markerLineWidth': 3,
            'markerLineColor': '#1bbc9b',
            'markerLineDasharray': [10, 5],
            'markerFillOpacity': 0.1,
            'markerFill': '#1bbc9b',
            'markerWidth': 1,
            'markerHeight': 1
        }
    });
    Map$1.addOnLoadHook('addHandler', 'boxZoom', MapBoxZoomHander);

    var PANOFFSET = 30;

    var MapAutoPanAtEdgeHandler = function(_Handler) {
        _inheritsLoose(MapAutoPanAtEdgeHandler, _Handler);

        function MapAutoPanAtEdgeHandler() {
            return _Handler.apply(this, arguments) || this;
        }

        var _proto = MapAutoPanAtEdgeHandler.prototype;

        _proto.addHooks = function addHooks() {
            if (!this.target) {
                return;
            }

            this.target.on('_mousemove', this._onMouseMove, this);
        };

        _proto.removeHooks = function removeHooks() {
            if (!this.target) {
                return;
            }

            this.target.off('_mousemove', this._onMouseMove, this);
        };

        _proto._onMouseMove = function _onMouseMove(event) {
            var map = this.target;

            if (map.options['autoPanAtEdge']) {
                var containerPoint = event.containerPoint;
                var containerExtent = map.getContainerExtent();

                if (containerExtent) {
                    var x = containerPoint.x,
                        y = containerPoint.y;
                    var xmax = containerExtent.xmax,
                        ymax = containerExtent.ymax;
                    var p;

                    if (x < PANOFFSET) {
                        p = [Math.abs(x - PANOFFSET), 0];
                    }

                    if (y < PANOFFSET) {
                        p = [0, Math.abs(y - PANOFFSET)];
                    }

                    if (x + PANOFFSET > xmax) {
                        p = [-Math.abs(x + PANOFFSET - xmax), 0];
                    }

                    if (y + PANOFFSET > ymax) {
                        p = [0, -Math.abs(y + PANOFFSET - ymax)];
                    }

                    if (p) {
                        map.panBy(p, {
                            duration: 1
                        });
                    }
                }
            }
        };

        return MapAutoPanAtEdgeHandler;
    }(Handler$1);

    Map$1.mergeOptions({
        'autoPanAtEdge': false
    });
    Map$1.addOnLoadHook('addHandler', 'autoPanAtEdge', MapAutoPanAtEdgeHandler);

    Map$1.include({
        animateTo: function animateTo(view, options, step) {
            var _this = this;

            if (options === void 0) {
                options = {};
            }

            if (isFunction(options)) {
                step = options;
                options = {};
            }

            var projection = this.getProjection(),
                currView = this.getView(),
                props = {};
            var empty = true;

            for (var p in view) {
                if (hasOwn(view, p) && !isNil(view[p]) && (p === 'prjCenter' || !isNil(currView[p]))) {
                    empty = false;

                    if (p === 'center') {
                        var from = new Coordinate(currView[p]).toFixed(7),
                            to = new Coordinate(view[p]).toFixed(7);

                        if (!from.equals(to)) {
                            props['center'] = [from, to];
                        }
                    } else if (p === 'prjCenter') {
                        var _from = new Coordinate(this._getPrjCenter());

                        var _to = new Coordinate(view[p]);

                        if (!_from.equals(_to)) {
                            props['prjCenter'] = [_from, _to];
                        }
                    } else if (currView[p] !== view[p] && p !== 'around') {
                        props[p] = [currView[p], view[p]];
                    }
                }
            }

            if (empty) {
                return null;
            }

            if (this._animPlayer) {
                if (this._isInternalAnimation) {
                    if (this._animPlayer.playState === 'running') {
                        this._animPlayer.pause();

                        this._prevAnimPlayer = this._animPlayer;
                    }
                } else {
                    delete this._prevAnimPlayer;

                    this._stopAnim(this._animPlayer);
                }
            }

            var zoomOrigin = view['around'] || new Point(this.width / 2, this.height / 2);

            var renderer = this._getRenderer(),
                framer = function framer(fn) {
                    renderer.callInNextFrame(fn);
                };

            var player = this._animPlayer = Animation.animate(props, {
                'easing': options['easing'] || 'out',
                'duration': options['duration'] || this.options['zoomAnimationDuration'],
                'framer': framer
            }, function(frame) {
                if (_this.isRemoved()) {
                    player.finish();
                    return;
                }

                if (player.playState === 'running') {
                    if (frame.styles['center']) {
                        var center = frame.styles['center'];

                        _this._setPrjCenter(projection.project(center));

                        _this.onMoving(_this._parseEventFromCoord(_this.getCenter()));
                    } else if (frame.styles['prjCenter']) {
                        var _center = frame.styles['prjCenter'];

                        _this._setPrjCenter(_center);

                        _this.onMoving(_this._parseEventFromCoord(_this.getCenter()));
                    }

                    if (!isNil(frame.styles['zoom'])) {
                        _this.onZooming(frame.styles['zoom'], zoomOrigin);
                    }

                    if (!isNil(frame.styles['pitch'])) {
                        _this.setPitch(frame.styles['pitch']);
                    }

                    if (!isNil(frame.styles['bearing'])) {
                        _this.setBearing(frame.styles['bearing']);
                    }

                    _this._fireEvent('animating');
                } else if (player.playState !== 'paused' || player === _this._mapAnimPlayer) {
                    if (!player._interupted) {
                        if (props['center']) {
                            _this._setPrjCenter(projection.project(props['center'][1]));
                        } else if (props['prjCenter']) {
                            _this._setPrjCenter(props['prjCenter'][1]);
                        }

                        if (!isNil(props['pitch'])) {
                            _this.setPitch(props['pitch'][1]);
                        }

                        if (!isNil(props['bearing'])) {
                            _this.setBearing(props['bearing'][1]);
                        }
                    }

                    _this._endAnim(player, props, zoomOrigin, options);
                }

                if (step) {
                    step(frame);
                }
            }, this);

            this._startAnim(props, zoomOrigin);

            return player;
        },
        _animateTo: function _animateTo(view, options, step) {
            if (options === void 0) {
                options = {};
            }

            if (this._mapAnimPlayer) {
                this._stopAnim(this._mapAnimPlayer);
            }

            this._isInternalAnimation = true;
            this._mapAnimPlayer = this.animateTo(view, options, step);
            delete this._isInternalAnimation;
            return this._mapAnimPlayer;
        },
        isAnimating: function isAnimating() {
            return !!this._animPlayer;
        },
        isRotating: function isRotating() {
            return this.isDragRotating() || !!this._animRotating;
        },
        _endAnim: function _endAnim(player, props, zoomOrigin, options) {
            delete this._animRotating;
            var evtType = player._interupted ? 'animateinterrupted' : 'animateend';

            if (player === this._animPlayer) {
                delete this._animPlayer;
            }

            if (player === this._mapAnimPlayer) {
                delete this._mapAnimPlayer;
            }

            if (props['center']) {
                var endCoord;

                if (player._interupted) {
                    endCoord = this.getCenter();
                } else {
                    endCoord = props['center'][1];
                }

                this.onMoveEnd(this._parseEventFromCoord(endCoord));
            } else if (props['prjCenter']) {
                var _endCoord;

                if (player._interupted) {
                    _endCoord = this._getPrjCenter();
                } else {
                    _endCoord = props['prjCenter'][1];
                }

                var event = this._parseEventFromCoord(this.getProjection().unproject(_endCoord));

                event['point2d'] = this._prjToPoint(_endCoord);
                this.onMoveEnd(event);
            }

            if (!isNil(props['zoom'])) {
                if (player._interupted) {
                    this.onZoomEnd(this.getZoom(), zoomOrigin);
                } else if (!options['wheelZoom']) {
                    this.onZoomEnd(props['zoom'][1], zoomOrigin);
                } else {
                    this.onZooming(props['zoom'][1], zoomOrigin);
                }
            }

            if (evtType) {
                this._fireEvent(evtType);
            }

            if (!isNil(props['pitch']) && !this.getPitch()) {
                this.getRenderer().setToRedraw();
            }

            this._resumePrev(player);
        },
        _startAnim: function _startAnim(props, zoomOrigin) {
            if (!this._animPlayer) {
                return;
            }

            if (props['center']) {
                this.onMoveStart();
            }

            if (props['zoom'] && !this.isZooming()) {
                this.onZoomStart(props['zoom'][1], zoomOrigin);
            }

            if (props['pitch'] || props['bearing']) {
                this._animRotating = true;
            }

            this._fireEvent('animatestart');

            this._animPlayer.play();
        },
        _stopAnim: function _stopAnim(player) {
            if (!player) {
                return;
            }

            delete this._animRotating;

            if (player.playState !== 'finished') {
                player._interupted = true;
                player.cancel();
            }

            if (player === this._animPlayer) {
                delete this._animPlayer;
            }

            if (player === this._mapAnimPlayer) {
                delete this._mapAnimPlayer;
            }
        },
        _resumePrev: function _resumePrev(player) {
            if (!this._prevAnimPlayer) {
                return;
            }

            var prevPlayer = this._prevAnimPlayer;

            if (prevPlayer.playState !== 'paused') {
                delete this._prevAnimPlayer;
            }

            if (player !== prevPlayer) {
                this._animPlayer = prevPlayer;
                prevPlayer.play();
            }
        }
    });

    var events = 'mousedown ' + 'mouseup ' + 'mouseover ' + 'mouseout ' + 'mouseenter ' + 'mouseleave ' + 'mousemove ' + 'click ' + 'dblclick ' + 'contextmenu ' + 'keypress ' + 'touchstart ' + 'touchmove ' + 'touchend ';
    Map$1.include({
        _registerDomEvents: function _registerDomEvents() {
            var dom = this._panels.mapWrapper || this._containerDOM;
            addDomEvent(dom, events, this._handleDOMEvent, this);
        },
        _removeDomEvents: function _removeDomEvents() {
            var dom = this._panels.mapWrapper || this._containerDOM;
            removeDomEvent(dom, events, this._handleDOMEvent, this);
        },
        _handleDOMEvent: function _handleDOMEvent(e) {
            var type = e.type;

            if (type === 'contextmenu') {
                preventDefault(e);
            }

            if (this._ignoreEvent(e)) {
                return;
            }

            var mimicClick = false;

            if (type === 'mousedown' || type === 'touchstart' && e.touches.length === 1) {
                this._mouseDownTime = now();
            } else if (type === 'click' || type === 'touchend' || type === 'contextmenu') {
                if (!this._mouseDownTime) {
                    return;
                } else {
                    var downTime = this._mouseDownTime;
                    delete this._mouseDownTime;
                    var time = now();

                    if (time - downTime > 300) {
                        if (type === 'click' || type === 'contextmenu') {
                            return;
                        }
                    } else if (type === 'touchend') {
                        mimicClick = true;
                    }
                }
            }

            this._fireDOMEvent(this, e, type);

            if (mimicClick) {
                if (this._clickTime && now() - this._clickTime <= 300) {
                    delete this._clickTime;

                    this._fireDOMEvent(this, e, 'dblclick');
                } else {
                    this._clickTime = now();

                    this._fireDOMEvent(this, e, 'click');
                }
            }
        },
        _ignoreEvent: function _ignoreEvent(domEvent) {
            if (!domEvent || !this._panels.control) {
                return false;
            }

            if (this._isEventOutMap(domEvent)) {
                return true;
            }

            var target = domEvent.srcElement || domEvent.target;
            var preTarget;

            if (target) {
                while (target && target !== this._containerDOM) {
                    if (target.className && target.className.indexOf && (target.className.indexOf('maptalks-control') >= 0 || target.className.indexOf('maptalks-ui') >= 0 && !preTarget['eventsPropagation'])) {
                        return true;
                    }

                    preTarget = target;
                    target = target.parentNode;
                }
            }

            return false;
        },
        _isEventOutMap: function _isEventOutMap(domEvent) {
            if (this.getPitch() > this.options['maxVisualPitch']) {
                var actualEvent = this._getActualEvent(domEvent);

                var eventPos = getEventContainerPoint(actualEvent, this._containerDOM);

                if (!this.getContainerExtent().contains(eventPos)) {
                    return true;
                }
            }

            return false;
        },
        _parseEvent: function _parseEvent(e, type) {
            if (!e) {
                return null;
            }

            var eventParam = {
                'domEvent': e
            };

            if (type !== 'keypress') {
                var actual = this._getActualEvent(e);

                if (actual) {
                    var containerPoint = getEventContainerPoint(actual, this._containerDOM);
                    eventParam = extend(eventParam, {
                        'coordinate': this.containerPointToCoord(containerPoint),
                        'containerPoint': containerPoint,
                        'viewPoint': this.containerPointToViewPoint(containerPoint),
                        'point2d': this._containerPointToPoint(containerPoint)
                    });
                }
            }

            return eventParam;
        },
        _parseEventFromCoord: function _parseEventFromCoord(coord) {
            var containerPoint = this.coordToContainerPoint(coord),
                viewPoint = this.containerPointToViewPoint(containerPoint);
            var e = {
                'coordinate': coord,
                'containerPoint': containerPoint,
                'viewPoint': viewPoint,
                'point2d': this.coordToPoint(coord)
            };
            return e;
        },
        _getActualEvent: function _getActualEvent(e) {
            return e.touches && e.touches.length > 0 ? e.touches[0] : e.changedTouches && e.changedTouches.length > 0 ? e.changedTouches[0] : e;
        },
        _fireDOMEvent: function _fireDOMEvent(target, e, type) {
            if (this.isRemoved()) {
                return;
            }

            var eventParam = this._parseEvent(e, type);

            this._fireEvent(type, eventParam);
        }
    });
    Map$1.addOnLoadHook('_registerDomEvents');

    Map$1.include({
        isFullScreen: function isFullScreen() {
            return !!(document.webkitIsFullScreen || document.mozFullScreen || document.msFullscreenElement || document.fullscreenElement);
        },
        requestFullScreen: function requestFullScreen(dom) {
            this._fireEvent('fullscreenstart');

            this._requestFullScreen(dom || this._containerDOM);

            this._fireEvent('fullscreenend');

            return this;
        },
        cancelFullScreen: function cancelFullScreen() {
            this._cancelFullScreen();

            this._fireEvent('cancelfullscreen');

            return this;
        },
        _requestFullScreen: function _requestFullScreen(dom) {
            if (dom.requestFullscreen) {
                dom.requestFullscreen();
            } else if (dom.mozRequestFullScreen) {
                dom.mozRequestFullScreen();
            } else if (dom.webkitRequestFullScreen) {
                dom.webkitRequestFullScreen();
            } else if (dom.msRequestFullScreen) {
                dom.msRequestFullScreen();
            } else {
                var features = 'fullscreen=1,status=no,resizable=yes,top=0,left=0,scrollbars=no,' + 'titlebar=no,menubar=no,location=no,toolbar=no,z-look=yes,' + 'width=' + (screen.availWidth - 8) + ',height=' + (screen.availHeight - 45);
                var newWin = window.open(location.href, '_blank', features);

                if (newWin !== null) {
                    window.opener = null;
                    window.close();
                }
            }
        },
        _cancelFullScreen: function _cancelFullScreen() {
            if (document.exitFullscreen) {
                document.exitFullscreen();
            } else if (document.mozCancelFullScreen) {
                document.mozCancelFullScreen();
            } else if (document.webkitCancelFullScreen) {
                document.webkitCancelFullScreen();
            } else {
                var features = 'fullscreen=no,status=yes,resizable=yes,scrollbars=no,' + 'titlebar=no,menubar=yes,location=yes,toolbar=yes,z-look=yes';
                var newWin = window.open(location.href, '_blank', features);

                if (newWin !== null) {
                    window.opener = null;
                    window.close();
                }
            }
        }
    });

    Map$1.include({
        panTo: function panTo(coordinate, options, step) {
            if (options === void 0) {
                options = {};
            }

            if (!coordinate) {
                return this;
            }

            if (isFunction(options)) {
                step = options;
                options = {};
            }

            coordinate = new Coordinate(coordinate);

            if (typeof options['animation'] === 'undefined' || options['animation']) {
                var prjCoord = this.getProjection().project(coordinate);
                return this._panAnimation(prjCoord, options['duration'], step);
            } else {
                this.setCenter(coordinate);
            }

            return this;
        },
        _panTo: function _panTo(prjCoord, options) {
            if (options === void 0) {
                options = {};
            }

            if (typeof options['animation'] === 'undefined' || options['animation']) {
                return this._panAnimation(prjCoord, options['duration']);
            } else {
                this.onMoveStart();

                this._setPrjCenter(prjCoord);

                this.onMoveEnd(this._parseEventFromCoord(this.getCenter()));
                return this;
            }
        },
        panBy: function panBy(offset, options, step) {
            if (options === void 0) {
                options = {};
            }

            if (!offset) {
                return this;
            }

            if (isFunction(options)) {
                step = options;
                options = {};
            }

            offset = new Point(offset);
            var containerExtent = this.getContainerExtent();
            var ymin = containerExtent.ymin;

            if (ymin > 0 && offset.y > 30) {
                var y = offset.y;
                offset.y = 30;
                offset.x = offset.x * 30 / y;
                console.warn('offset is limited to panBy when pitch is above maxPitch');
            }

            this.onMoveStart();

            if (typeof options['animation'] === 'undefined' || options['animation']) {
                offset = offset.multi(-1);

                var target = this._containerPointToPrj(new Point(this.width / 2 + offset.x, this.height / 2 + offset.y));

                this._panAnimation(target, options['duration'], step);
            } else {
                this._offsetCenterByPixel(offset);

                this.onMoveEnd(this._parseEventFromCoord(this.getCenter()));
            }

            return this;
        },
        _panAnimation: function _panAnimation(target, t, cb) {
            return this._animateTo({
                'prjCenter': target
            }, {
                'duration': t || this.options['panAnimationDuration']
            }, cb);
        }
    });

    Geometry.fromJSON = function(json) {
        if (Array.isArray(json)) {
            var result = [];

            for (var i = 0, len = json.length; i < len; i++) {
                var c = Geometry.fromJSON(json[i]);

                if (Array.isArray(json)) {
                    result = result.concat(c);
                } else {
                    result.push(c);
                }
            }

            return result;
        }

        if (json && !json['feature']) {
            return GeoJSON.toGeometry(json);
        }

        var geometry;

        if (json['subType']) {
            geometry = Geometry.getJSONClass(json['subType']).fromJSON(json);

            if (!isNil(json['feature']['id'])) {
                geometry.setId(json['feature']['id']);
            }
        } else {
            geometry = GeoJSON.toGeometry(json['feature']);

            if (json['options']) {
                geometry.config(json['options']);
            }
        }

        if (json['symbol']) {
            geometry.setSymbol(json['symbol']);
        }

        if (json['infoWindow']) {
            geometry.setInfoWindow(json['infoWindow']);
        }

        return geometry;
    };

    Layer.fromJSON = function(layerJSON) {
        if (!layerJSON) {
            return null;
        }

        var layerType = layerJSON['type'];
        var clazz = Layer.getJSONClass(layerType);

        if (!clazz || !clazz.fromJSON) {
            throw new Error('unsupported layer type:' + layerType);
        }

        return clazz.fromJSON(layerJSON);
    };

    Map$1.include({
        'JSON_VERSION': '1.0',
        toJSON: function toJSON(options) {
            if (!options) {
                options = {};
            }

            var json = {
                'jsonVersion': this['JSON_VERSION'],
                'version': this.VERSION,
                'extent': this.getExtent().toJSON()
            };
            json['options'] = this.config();
            json['options']['center'] = this.getCenter();
            json['options']['zoom'] = this.getZoom();
            json['options']['bearing'] = this.getBearing();
            json['options']['pitch'] = this.getPitch();
            var baseLayer = this.getBaseLayer();

            if ((isNil(options['baseLayer']) || options['baseLayer']) && baseLayer) {
                json['baseLayer'] = baseLayer.toJSON(options['baseLayer']);
            }

            var extraLayerOptions = {};

            if (options['clipExtent']) {
                if (options['clipExtent'] === true) {
                    extraLayerOptions['clipExtent'] = this.getExtent();
                } else {
                    extraLayerOptions['clipExtent'] = options['clipExtent'];
                }
            }

            var layersJSON = [];

            if (isNil(options['layers']) || options['layers'] && !Array.isArray(options['layers'])) {
                var layers = this.getLayers();

                for (var i = 0, len = layers.length; i < len; i++) {
                    if (!layers[i].toJSON) {
                        continue;
                    }

                    var opts = extend({}, isObject(options['layers']) ? options['layers'] : {}, extraLayerOptions);
                    layersJSON.push(layers[i].toJSON(opts));
                }

                json['layers'] = layersJSON;
            } else if (isArrayHasData(options['layers'])) {
                var _layers = options['layers'];

                for (var _i = 0; _i < _layers.length; _i++) {
                    var exportOption = _layers[_i];
                    var layer = this.getLayer(exportOption['id']);

                    if (!layer.toJSON) {
                        continue;
                    }

                    var _opts = extend({}, exportOption['options'], extraLayerOptions);

                    layersJSON.push(layer.toJSON(_opts));
                }

                json['layers'] = layersJSON;
            } else {
                json['layers'] = [];
            }

            return json;
        }
    });

    Map$1.fromJSON = function(container, profile, options) {
        if (!container || !profile) {
            return null;
        }

        if (!options) {
            options = {};
        }

        var map = new Map$1(container, profile['options']);

        if (isNil(options['baseLayer']) || options['baseLayer']) {
            var baseLayer = Layer.fromJSON(profile['baseLayer']);

            if (baseLayer) {
                map.setBaseLayer(baseLayer);
            }
        }

        if (isNil(options['layers']) || options['layers']) {
            var layers = [];
            var layerJSONs = profile['layers'];

            for (var i = 0; i < layerJSONs.length; i++) {
                var layer = Layer.fromJSON(layerJSONs[i]);
                layers.push(layer);
            }

            map.addLayer(layers);
        }

        return map;
    };

    Map$1.include({
        computeLength: function computeLength(coord1, coord2) {
            if (!this.getProjection()) {
                return null;
            }

            var p1 = new Coordinate(coord1),
                p2 = new Coordinate(coord2);

            if (p1.equals(p2)) {
                return 0;
            }

            return this.getProjection().measureLength(p1, p2);
        },
        computeGeometryLength: function computeGeometryLength(geometry) {
            return geometry._computeGeodesicLength(this.getProjection());
        },
        computeGeometryArea: function computeGeometryArea(geometry) {
            return geometry._computeGeodesicArea(this.getProjection());
        },
        identify: function identify(opts, callback) {
            if (!opts) {
                return this;
            }

            var reqLayers = opts['layers'];

            if (!isArrayHasData(reqLayers)) {
                return this;
            }

            var layers = [];

            for (var i = 0, len = reqLayers.length; i < len; i++) {
                if (isString(reqLayers[i])) {
                    layers.push(this.getLayer(reqLayers[i]));
                } else {
                    layers.push(reqLayers[i]);
                }
            }

            var coordinate = new Coordinate(opts['coordinate']);
            var options = extend({}, opts);
            var hits = [];

            for (var _i = layers.length - 1; _i >= 0; _i--) {
                if (opts['count'] && hits.length >= opts['count']) {
                    break;
                }

                var layer = layers[_i];

                if (!layer || !layer.getMap() || !opts['includeInvisible'] && !layer.isVisible() || !opts['includeInternals'] && layer.getId().indexOf(INTERNAL_LAYER_PREFIX) >= 0) {
                    continue;
                }

                var layerHits = layer.identify(coordinate, options);

                if (layerHits) {
                    if (Array.isArray(layerHits)) {
                        pushIn(hits, layerHits);
                    } else {
                        hits.push(layerHits);
                    }
                }
            }

            callback.call(this, hits);
            return this;
        }
    });

    Map$1.include({
        _zoom: function _zoom(nextZoom, origin) {
            if (!this.options['zoomable'] || this.isZooming()) {
                return;
            }

            origin = this._checkZoomOrigin(origin);
            nextZoom = this._checkZoom(nextZoom);
            this.onZoomStart(nextZoom, origin);
            this._frameZoom = this.getZoom();
            this.onZoomEnd(nextZoom, origin);
        },
        _zoomAnimation: function _zoomAnimation(nextZoom, origin, startScale) {
            if (!this.options['zoomable'] || this.isZooming()) {
                return;
            }

            nextZoom = this._checkZoom(nextZoom);

            if (this.getZoom() === nextZoom) {
                return;
            }

            origin = this._checkZoomOrigin(origin);

            this._startZoomAnim(nextZoom, origin, startScale);
        },
        _checkZoomOrigin: function _checkZoomOrigin(origin) {
            if (!origin || this.options['zoomInCenter']) {
                origin = new Point(this.width / 2, this.height / 2);
            }

            if (this.options['zoomOrigin']) {
                origin = new Point(this.options['zoomOrigin']);
            }

            return origin;
        },
        _startZoomAnim: function _startZoomAnim(nextZoom, origin, startScale) {
            if (isNil(startScale)) {
                startScale = 1;
            }

            var endScale = this._getResolution(this._startZoomVal) / this._getResolution(nextZoom);

            var duration = this.options['zoomAnimationDuration'] * Math.abs(endScale - startScale) / Math.abs(endScale - 1);
            this._frameZoom = this._startZoomVal;

            this._animateTo({
                'zoom': nextZoom,
                'around': origin
            }, {
                'continueOnViewChanged': true,
                'duration': duration
            });
        },
        onZoomStart: function onZoomStart(nextZoom, origin) {
            if (!this.options['zoomable'] || this.isZooming()) {
                return;
            }

            if (this._mapAnimPlayer) {
                this._stopAnim(this._mapAnimPlayer);
            }

            this._zooming = true;
            this._startZoomVal = this.getZoom();
            this._startZoomCoord = this._containerPointToPrj(origin);

            this._fireEvent('zoomstart', {
                'from': this._startZoomVal,
                'to': nextZoom
            });
        },
        onZooming: function onZooming(nextZoom, origin, startScale) {
            if (!this.options['zoomable']) {
                return;
            }

            var frameZoom = this._frameZoom;

            if (frameZoom === nextZoom) {
                return;
            }

            if (isNil(startScale)) {
                startScale = 1;
            }

            this._zoomTo(nextZoom, origin);

            var res = this.getResolution(nextZoom),
                fromRes = this.getResolution(this._startZoomVal),
                scale = fromRes / res / startScale,
                startPoint = this._prjToContainerPoint(this._startZoomCoord, this._startZoomVal);

            var offset = this.getViewPoint();

            if (!this.isRotating() && !startPoint.equals(origin) && scale !== 1) {
                var pitch = this.getPitch();

                var originOffset = startPoint._sub(origin)._multi(1 / (1 - scale));

                if (pitch) {
                    originOffset.y /= Math.cos(pitch * Math.PI / 180);
                }

                origin = origin.add(originOffset);
            }

            var matrix = {
                'view': [scale, 0, 0, scale, (origin.x - offset.x) * (1 - scale), (origin.y - offset.y) * (1 - scale)]
            };
            var dpr = this.getDevicePixelRatio();

            if (dpr !== 1) {
                origin = origin.multi(dpr);
            }

            matrix['container'] = [scale, 0, 0, scale, origin.x * (1 - scale), origin.y * (1 - scale)];

            this._fireEvent('zooming', {
                'from': this._startZoomVal,
                'to': nextZoom,
                'origin': origin,
                'matrix': matrix
            });

            this._frameZoom = nextZoom;
        },
        onZoomEnd: function onZoomEnd(nextZoom, origin) {
            if (!this.options['zoomable']) {
                return;
            }

            var startZoomVal = this._startZoomVal;

            this._zoomTo(nextZoom, origin);

            this._zooming = false;

            this._getRenderer().onZoomEnd();

            this._fireEvent('zoomend', {
                'from': startZoomVal,
                'to': nextZoom
            });

            if (!this._verifyExtent(this._getPrjCenter())) {
                this._panTo(this._prjMaxExtent.getCenter());
            }
        },
        _zoomTo: function _zoomTo(nextZoom, origin) {
            this._zoomLevel = nextZoom;

            this._calcMatrices();

            if (origin) {
                this._setPrjCoordAtContainerPoint(this._startZoomCoord, origin);
            }
        },
        _checkZoom: function _checkZoom(nextZoom) {
            var maxZoom = this.getMaxZoom(),
                minZoom = this.getMinZoom();

            if (nextZoom < minZoom) {
                nextZoom = minZoom;
            }

            if (nextZoom > maxZoom) {
                nextZoom = maxZoom;
            }

            return nextZoom;
        }
    });

    function perspective(out, fovy, aspect, near, far) {
        var f = 1.0 / Math.tan(fovy / 2),
            nf = 1 / (near - far);
        out[0] = f / aspect;
        out[1] = 0;
        out[2] = 0;
        out[3] = 0;
        out[4] = 0;
        out[5] = f;
        out[6] = 0;
        out[7] = 0;
        out[8] = 0;
        out[9] = 0;
        out[10] = (far + near) * nf;
        out[11] = -1;
        out[12] = 0;
        out[13] = 0;
        out[14] = 2 * far * near * nf;
        out[15] = 0;
        return out;
    }

    function translate(out, a, v) {
        var x = v[0],
            y = v[1],
            z = v[2],
            a00,
            a01,
            a02,
            a03,
            a10,
            a11,
            a12,
            a13,
            a20,
            a21,
            a22,
            a23;

        if (a === out) {
            out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
            out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
            out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
            out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
        } else {
            a00 = a[0];
            a01 = a[1];
            a02 = a[2];
            a03 = a[3];
            a10 = a[4];
            a11 = a[5];
            a12 = a[6];
            a13 = a[7];
            a20 = a[8];
            a21 = a[9];
            a22 = a[10];
            a23 = a[11];
            out[0] = a00;
            out[1] = a01;
            out[2] = a02;
            out[3] = a03;
            out[4] = a10;
            out[5] = a11;
            out[6] = a12;
            out[7] = a13;
            out[8] = a20;
            out[9] = a21;
            out[10] = a22;
            out[11] = a23;
            out[12] = a00 * x + a10 * y + a20 * z + a[12];
            out[13] = a01 * x + a11 * y + a21 * z + a[13];
            out[14] = a02 * x + a12 * y + a22 * z + a[14];
            out[15] = a03 * x + a13 * y + a23 * z + a[15];
        }

        return out;
    }

    function scale(out, a, v) {
        var x = v[0],
            y = v[1],
            z = v[2];
        out[0] = a[0] * x;
        out[1] = a[1] * x;
        out[2] = a[2] * x;
        out[3] = a[3] * x;
        out[4] = a[4] * y;
        out[5] = a[5] * y;
        out[6] = a[6] * y;
        out[7] = a[7] * y;
        out[8] = a[8] * z;
        out[9] = a[9] * z;
        out[10] = a[10] * z;
        out[11] = a[11] * z;
        out[12] = a[12];
        out[13] = a[13];
        out[14] = a[14];
        out[15] = a[15];
        return out;
    }

    function rotateX(out, a, rad) {
        var s = Math.sin(rad),
            c = Math.cos(rad),
            a10 = a[4],
            a11 = a[5],
            a12 = a[6],
            a13 = a[7],
            a20 = a[8],
            a21 = a[9],
            a22 = a[10],
            a23 = a[11];

        if (a !== out) {
            out[0] = a[0];
            out[1] = a[1];
            out[2] = a[2];
            out[3] = a[3];
            out[12] = a[12];
            out[13] = a[13];
            out[14] = a[14];
            out[15] = a[15];
        }

        out[4] = a10 * c + a20 * s;
        out[5] = a11 * c + a21 * s;
        out[6] = a12 * c + a22 * s;
        out[7] = a13 * c + a23 * s;
        out[8] = a20 * c - a10 * s;
        out[9] = a21 * c - a11 * s;
        out[10] = a22 * c - a12 * s;
        out[11] = a23 * c - a13 * s;
        return out;
    }

    function rotateZ(out, a, rad) {
        var s = Math.sin(rad),
            c = Math.cos(rad),
            a00 = a[0],
            a01 = a[1],
            a02 = a[2],
            a03 = a[3],
            a10 = a[4],
            a11 = a[5],
            a12 = a[6],
            a13 = a[7];

        if (a !== out) {
            out[8] = a[8];
            out[9] = a[9];
            out[10] = a[10];
            out[11] = a[11];
            out[12] = a[12];
            out[13] = a[13];
            out[14] = a[14];
            out[15] = a[15];
        }

        out[0] = a00 * c + a10 * s;
        out[1] = a01 * c + a11 * s;
        out[2] = a02 * c + a12 * s;
        out[3] = a03 * c + a13 * s;
        out[4] = a10 * c - a00 * s;
        out[5] = a11 * c - a01 * s;
        out[6] = a12 * c - a02 * s;
        out[7] = a13 * c - a03 * s;
        return out;
    }

    function multiply(out, a, b) {
        var a00 = a[0],
            a01 = a[1],
            a02 = a[2],
            a03 = a[3],
            a10 = a[4],
            a11 = a[5],
            a12 = a[6],
            a13 = a[7],
            a20 = a[8],
            a21 = a[9],
            a22 = a[10],
            a23 = a[11],
            a30 = a[12],
            a31 = a[13],
            a32 = a[14],
            a33 = a[15];
        var b0 = b[0],
            b1 = b[1],
            b2 = b[2],
            b3 = b[3];
        out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
        out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
        out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
        out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
        b0 = b[4];
        b1 = b[5];
        b2 = b[6];
        b3 = b[7];
        out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
        out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
        out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
        out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
        b0 = b[8];
        b1 = b[9];
        b2 = b[10];
        b3 = b[11];
        out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
        out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
        out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
        out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
        b0 = b[12];
        b1 = b[13];
        b2 = b[14];
        b3 = b[15];
        out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
        out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
        out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
        out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
        return out;
    }

    function invert(out, a) {
        var a00 = a[0],
            a01 = a[1],
            a02 = a[2],
            a03 = a[3],
            a10 = a[4],
            a11 = a[5],
            a12 = a[6],
            a13 = a[7],
            a20 = a[8],
            a21 = a[9],
            a22 = a[10],
            a23 = a[11],
            a30 = a[12],
            a31 = a[13],
            a32 = a[14],
            a33 = a[15],
            b00 = a00 * a11 - a01 * a10,
            b01 = a00 * a12 - a02 * a10,
            b02 = a00 * a13 - a03 * a10,
            b03 = a01 * a12 - a02 * a11,
            b04 = a01 * a13 - a03 * a11,
            b05 = a02 * a13 - a03 * a12,
            b06 = a20 * a31 - a21 * a30,
            b07 = a20 * a32 - a22 * a30,
            b08 = a20 * a33 - a23 * a30,
            b09 = a21 * a32 - a22 * a31,
            b10 = a21 * a33 - a23 * a31,
            b11 = a22 * a33 - a23 * a32,
            det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;

        if (!det) {
            return null;
        }

        det = 1.0 / det;
        out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
        out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
        out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
        out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
        out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
        out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
        out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
        out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
        out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
        out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
        out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
        out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
        out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
        out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
        out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
        out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
        return out;
    }

    function identity(out) {
        out[0] = 1;
        out[1] = 0;
        out[2] = 0;
        out[3] = 0;
        out[4] = 0;
        out[5] = 1;
        out[6] = 0;
        out[7] = 0;
        out[8] = 0;
        out[9] = 0;
        out[10] = 1;
        out[11] = 0;
        out[12] = 0;
        out[13] = 0;
        out[14] = 0;
        out[15] = 1;
        return out;
    }

    function copy(out, a) {
        out[0] = a[0];
        out[1] = a[1];
        out[2] = a[2];
        out[3] = a[3];
        out[4] = a[4];
        out[5] = a[5];
        out[6] = a[6];
        out[7] = a[7];
        out[8] = a[8];
        out[9] = a[9];
        out[10] = a[10];
        out[11] = a[11];
        out[12] = a[12];
        out[13] = a[13];
        out[14] = a[14];
        out[15] = a[15];
        return out;
    }

    function set$2(out, x, y, z) {
        out[0] = x;
        out[1] = y;
        out[2] = z;
        return out;
    }

    function add(out, a, b) {
        out[0] = a[0] + b[0];
        out[1] = a[1] + b[1];
        out[2] = a[2] + b[2];
        return out;
    }

    function subtract(out, a, b) {
        out[0] = a[0] - b[0];
        out[1] = a[1] - b[1];
        out[2] = a[2] - b[2];
        return out;
    }

    function length(a) {
        var x = a[0],
            y = a[1],
            z = a[2];
        return Math.sqrt(x * x + y * y + z * z);
    }

    function normalize(out, a) {
        var x = a[0],
            y = a[1],
            z = a[2];
        var len = x * x + y * y + z * z;

        if (len > 0) {
            len = 1 / Math.sqrt(len);
            out[0] = a[0] * len;
            out[1] = a[1] * len;
            out[2] = a[2] * len;
        }

        return out;
    }

    function dot(a, b) {
        return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
    }

    function scale$1(out, a, b) {
        out[0] = a[0] * b;
        out[1] = a[1] * b;
        out[2] = a[2] * b;
        return out;
    }

    function cross(out, a, b) {
        var ax = a[0],
            ay = a[1],
            az = a[2],
            bx = b[0],
            by = b[1],
            bz = b[2];
        out[0] = ay * bz - az * by;
        out[1] = az * bx - ax * bz;
        out[2] = ax * by - ay * bx;
        return out;
    }

    function distance(a, b) {
        var x = b[0] - a[0];
        var y = b[1] - a[1];
        var z = b[2] - a[2];
        return Math.hypot ? Math.hypot(x, y, z) : hypot(x, y, z);
    }

    function transformMat4(out, a, m) {
        var x = a[0],
            y = a[1],
            z = a[2];
        var w = m[3] * x + m[7] * y + m[11] * z + m[15];
        w = w || 1.0;
        out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
        out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
        out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
        return out;
    }

    function hypot() {
        var y = 0;
        var i = arguments.length;

        while (i--) {
            y += arguments[i] * arguments[i];
        }

        return Math.sqrt(y);
    }

    function applyMatrix(out, v, e) {
        var x = v[0],
            y = v[1],
            z = v[2];
        var w = 1 / (e[3] * x + e[7] * y + e[11] * z + e[15]);
        out[0] = (e[0] * x + e[4] * y + e[8] * z + e[12]) * w;
        out[1] = (e[1] * x + e[5] * y + e[9] * z + e[13]) * w;
        out[2] = (e[2] * x + e[6] * y + e[10] * z + e[14]) * w;
        return out;
    }

    function matrixToQuaternion(out, te) {
        var m11 = te[0],
            m12 = te[4],
            m13 = te[8],
            m21 = te[1],
            m22 = te[5],
            m23 = te[9],
            m31 = te[2],
            m32 = te[6],
            m33 = te[10],
            trace = m11 + m22 + m33;
        var s;

        if (trace > 0) {
            s = 0.5 / Math.sqrt(trace + 1.0);
            out.w = 0.25 / s;
            out.x = (m32 - m23) * s;
            out.y = (m13 - m31) * s;
            out.z = (m21 - m12) * s;
        } else if (m11 > m22 && m11 > m33) {
            s = 2.0 * Math.sqrt(1.0 + m11 - m22 - m33);
            out.w = (m32 - m23) / s;
            out.x = 0.25 * s;
            out.y = (m12 + m21) / s;
            out.z = (m13 + m31) / s;
        } else if (m22 > m33) {
            s = 2.0 * Math.sqrt(1.0 + m22 - m11 - m33);
            out.w = (m13 - m31) / s;
            out.x = (m12 + m21) / s;
            out.y = 0.25 * s;
            out.z = (m23 + m32) / s;
        } else {
            s = 2.0 * Math.sqrt(1.0 + m33 - m11 - m22);
            out.w = (m21 - m12) / s;
            out.x = (m13 + m31) / s;
            out.y = (m23 + m32) / s;
            out.z = 0.25 * s;
        }

        return this;
    }

    function quaternionToMatrix(out, q) {
        var te = out;
        var x = q.x,
            y = q.y,
            z = q.z,
            w = q.w;
        var x2 = x + x,
            y2 = y + y,
            z2 = z + z;
        var xx = x * x2,
            xy = x * y2,
            xz = x * z2;
        var yy = y * y2,
            yz = y * z2,
            zz = z * z2;
        var wx = w * x2,
            wy = w * y2,
            wz = w * z2;
        te[0] = 1 - (yy + zz);
        te[4] = xy - wz;
        te[8] = xz + wy;
        te[1] = xy + wz;
        te[5] = 1 - (xx + zz);
        te[9] = yz - wx;
        te[2] = xz - wy;
        te[6] = yz + wx;
        te[10] = 1 - (xx + yy);
        te[3] = 0;
        te[7] = 0;
        te[11] = 0;
        te[12] = 0;
        te[13] = 0;
        te[14] = 0;
        te[15] = 1;
        return te;
    }

    function setPosition(out, v) {
        var te = out;
        te[12] = v[0];
        te[13] = v[1];
        te[14] = v[2];
        return out;
    }

    function lookAt(te, eye, target, up) {
        var x = [0, 0, 0];
        var y = [0, 0, 0];
        var z = [0, 0, 0];
        subtract(z, eye, target);

        if (length(z) === 0) {
            z[2] = 1;
        }

        normalize(z, z);
        cross(x, up, z);

        if (length(z) === 0) {
            if (Math.abs(up[2]) === 1) {
                z[0] += 0.0001;
            } else {
                z[2] += 0.0001;
            }

            normalize(z, z);
            cross(x, up, z);
        }

        normalize(x, x);
        cross(y, z, x);
        te[0] = x[0];
        te[4] = y[0];
        te[8] = z[0];
        te[1] = x[1];
        te[5] = y[1];
        te[9] = z[1];
        te[2] = x[2];
        te[6] = y[2];
        te[10] = z[2];
        return te;
    }

    var RADIAN$1 = Math.PI / 180;
    var DEFAULT_FOV = 0.6435011087932844;
    var TEMP_COORD = new Coordinate(0, 0);
    Map$1.include({
        getFov: function getFov() {
            if (!this._fov) {
                this._fov = DEFAULT_FOV;
            }

            return this._fov / RADIAN$1;
        },
        setFov: function setFov(fov) {
            if (this.isZooming()) {
                return this;
            }

            fov = Math.max(0.01, Math.min(60, fov));
            if (this._fov === fov) return this;
            var from = this.getFov();
            this._fov = fov * RADIAN$1;

            this._calcMatrices();

            this._renderLayers();

            this._fireEvent('fovchange', {
                'from': from,
                'to': this.getFov()
            });

            return this;
        },
        getBearing: function getBearing() {
            if (!this._angle) {
                return 0;
            }

            return -this._angle / RADIAN$1;
        },
        setBearing: function setBearing(bearing) {
            if (Browser$1.ie9) {
                throw new Error('map can\'t rotate in IE9.');
            }

            var b = -wrap(bearing, -180, 180) * RADIAN$1;
            if (this._angle === b) return this;
            var from = this.getBearing();

            this._fireEvent('rotatestart', {
                'from': from,
                'to': b
            });

            this._angle = b;

            this._calcMatrices();

            this._renderLayers();

            this._fireEvent('rotate', {
                'from': from,
                'to': b
            });

            this._fireEvent('rotateend', {
                'from': from,
                'to': b
            });

            return this;
        },
        getPitch: function getPitch() {
            if (!this._pitch) {
                return 0;
            }

            return this._pitch / Math.PI * 180;
        },
        setPitch: function setPitch(pitch) {
            if (Browser$1.ie9) {
                throw new Error('map can\'t tilt in IE9.');
            }

            var p = clamp(pitch, 0, this.options['maxPitch']) * RADIAN$1;
            if (this._pitch === p) return this;
            var from = this.getPitch();

            this._fireEvent('pitchstart', {
                'from': from,
                'to': p
            });

            this._pitch = p;

            this._calcMatrices();

            this._renderLayers();

            this._fireEvent('pitch', {
                'from': from,
                'to': p
            });

            this._fireEvent('pitchend', {
                'from': from,
                'to': p
            });

            return this;
        },
        isTransforming: function isTransforming() {
            return !!(this._pitch || this._angle);
        },
        getFrustumAltitude: function getFrustumAltitude() {
            return this._frustumAltitude;
        },
        _calcFrustumAltitude: function _calcFrustumAltitude() {
            var pitch = 90 - this.getPitch();
            var fov = this.getFov() / 2;
            var cameraAlt = this.cameraPosition ? this.cameraPosition[2] : 0;

            if (fov <= pitch) {
                return cameraAlt;
            }

            fov = Math.PI * fov / 180;
            var d1 = new Point(this.cameraPosition).distanceTo(new Point(this.cameraLookAt)),
                d2 = cameraAlt * Math.tan(fov * 2);
            var d = Math.tan(fov) * (d1 + d2);
            return cameraAlt + d;
        },
        _pointToContainerPoint: function() {
            var a = [0, 0, 0];
            return function(point, zoom, altitude, out) {
                if (altitude === void 0) {
                    altitude = 0;
                }

                point = this._pointToPoint(point, zoom, out);

                if (this.isTransforming() || altitude) {
                    altitude *= this._getResolution(zoom) / this._getResolution();
                    var _scale = this._glScale;
                    set$2(a, point.x * _scale, point.y * _scale, altitude * _scale);

                    var t = this._projIfBehindCamera(a, this.cameraPosition, this.cameraForward);

                    applyMatrix(t, t, this.projViewMatrix);
                    var w2 = this.width / 2,
                        h2 = this.height / 2;
                    t[0] = t[0] * w2 + w2;
                    t[1] = -(t[1] * h2) + h2;

                    if (out) {
                        out.x = t[0];
                        out.y = t[1];
                        return out;
                    }

                    return new Point(t[0], t[1]);
                } else {
                    var centerPoint = this._prjToPoint(this._getPrjCenter(), undefined, TEMP_COORD);

                    if (out) {
                        out.x = point.x;
                        out.y = point.y;
                    } else {
                        out = point;
                    }

                    out._sub(centerPoint.x, centerPoint.y);

                    out.set(out.x, -out.y);
                    return out._add(this.width / 2, this.height / 2);
                }
            };
        }(),
        _projIfBehindCamera: function() {
            var vectorFromCam = new Array(3);
            var proj = new Array(3);
            var sub = new Array(3);
            return function(position, cameraPos, camForward) {
                subtract(vectorFromCam, position, cameraPos);
                var camNormDot = dot(camForward, vectorFromCam);

                if (camNormDot <= 0) {
                    scale$1(proj, camForward, camNormDot * 1.01);
                    add(position, cameraPos, subtract(sub, vectorFromCam, proj));
                }

                return position;
            };
        }(),
        _containerPointToPoint: function() {
            var cp = [0, 0, 0],
                coord0 = [0, 0, 0, 1],
                coord1 = [0, 0, 0, 1];
            return function(p, zoom, out) {
                if (this.isTransforming()) {
                    var w2 = this.width / 2 || 1,
                        h2 = this.height / 2 || 1;
                    set$2(cp, (p.x - w2) / w2, (h2 - p.y) / h2, 0);
                    set$2(coord0, cp[0], cp[1], 0);
                    set$2(coord1, cp[0], cp[1], 1);
                    coord0[3] = coord1[3] = 1;
                    applyMatrix(coord0, coord0, this.projViewMatrixInverse);
                    applyMatrix(coord1, coord1, this.projViewMatrixInverse);
                    var x0 = coord0[0];
                    var x1 = coord1[0];
                    var y0 = coord0[1];
                    var y1 = coord1[1];
                    var z0 = coord0[2];
                    var z1 = coord1[2];
                    var t = z0 === z1 ? 0 : (0 - z0) / (z1 - z0);

                    var _x = interpolate(x0, x1, t);

                    var _y = interpolate(y0, y1, t);

                    if (out) {
                        out.x = _x;
                        out.y = _y;
                    } else {
                        out = new Point(_x, _y);
                    }

                    out._multi(1 / this._glScale);

                    return zoom === undefined || this.getZoom() === zoom ? out : this._pointToPointAtZoom(out, zoom, out);
                }

                var centerPoint = this._prjToPoint(this._getPrjCenter(), zoom, out),
                    scale$$1 = zoom !== undefined ? this._getResolution() / this._getResolution(zoom) : 1;

                var x = scale$$1 * (p.x - this.width / 2),
                    y = scale$$1 * (p.y - this.height / 2);
                return centerPoint._add(x, -y);
            };
        }(),
        _calcMatrices: function() {
            var m1 = createMat4();
            return function() {
                delete this._mapRes;
                delete this._mapGlRes;
                delete this._mapExtent2D;
                delete this._mapGlExtent2D;
                var size = this.getSize();
                var w = size.width || 1,
                    h = size.height || 1;
                this._glScale = this.getGLScale();
                var pitch = this.getPitch() * Math.PI / 180;

                var worldMatrix = this._getCameraWorldMatrix();

                var fov = this.getFov() * Math.PI / 180;

                var farZ = this._getCameraFar(fov, this.getPitch());

                this.cameraFar = farZ;
                this.cameraNear = Math.max(this._glScale * this.getResolution(this.getGLZoom()) * Math.cos(pitch), 0.1);
                var projMatrix = this.projMatrix || createMat4();
                perspective(projMatrix, fov, w / h, this.cameraNear, farZ);
                this.projMatrix = projMatrix;
                this.viewMatrix = invert(this.viewMatrix || createMat4(), worldMatrix);
                this.projViewMatrix = multiply(this.projViewMatrix || createMat4(), projMatrix, this.viewMatrix);

                this._calcCascadeMatrixes();

                this.projViewMatrixInverse = multiply(this.projViewMatrixInverse || createMat4(), worldMatrix, invert(m1, projMatrix));
                this.domCssMatrix = this._calcDomMatrix();
                this._frustumAltitude = this._calcFrustumAltitude();
                this._mapRes = this._getResolution();
                this._mapGlRes = this._getResolution(this.getGLZoom());
                this._mapExtent2D = this._get2DExtent();
                this._mapGlExtent2D = this._get2DExtent(this.getGLZoom());
            };
        }(),
        _getCameraFar: function _getCameraFar(fov, pitch) {
            var cameraCenterDistance = this.cameraCenterDistance = distance(this.cameraPosition, this.cameraLookAt);
            var farZ = cameraCenterDistance;

            if (pitch > 0) {
                pitch = pitch * Math.PI / 180;
                var y;

                if (2 / Math.PI - pitch <= fov / 2) {
                    y = 4 * cameraCenterDistance;
                } else {
                    var tanFov = Math.tan(fov / 2);
                    var tanP = Math.tan(pitch);
                    y = cameraCenterDistance * tanFov / (1 / tanP - tanFov);
                }

                farZ += y;
            }

            return farZ + 1.0;
        },
        _calcCascadeMatrixes: function() {
            var projMatrix = createMat4();

            function cal(curPitch, pitch, out) {
                var w = this.width;
                var h = this.height;
                var fov = this.getFov() * Math.PI / 180;

                var farZ = this._getCameraFar(fov, pitch);

                var cameraCenterDistance = this.cameraCenterDistance;
                farZ = cameraCenterDistance + (farZ - cameraCenterDistance) / Math.cos((90 - pitch) * Math.PI / 180) * Math.cos((90 - curPitch) * Math.PI / 180);
                perspective(projMatrix, fov, w / h, 0.1, farZ);
                var viewMatrix = this.viewMatrix;
                return multiply(out, projMatrix, viewMatrix);
            }

            return function() {
                var pitch = this.getPitch();
                var cascadePitch0 = this.options['cascadePitches'][0];
                var cascadePitch1 = this.options['cascadePitches'][1];
                var projViewMatrix0 = this.cascadeFrustumMatrix0 = this.cascadeFrustumMatrix0 || createMat4();
                var projViewMatrix1 = this.cascadeFrustumMatrix1 = this.cascadeFrustumMatrix1 || createMat4();

                if (pitch > cascadePitch0) {
                    cal.call(this, pitch, cascadePitch0, projViewMatrix0);
                } else {
                    copy(this.cascadeFrustumMatrix0, this.projViewMatrix);
                }

                if (pitch > cascadePitch1) {
                    cal.call(this, pitch, cascadePitch1, projViewMatrix1);
                } else {
                    copy(this.cascadeFrustumMatrix1, this.cascadeFrustumMatrix0);
                }
            };
        }(),
        _calcDomMatrix: function() {
            var m = createMat4(),
                m1 = createMat4(),
                minusY = [1, -1, 1],
                arr = [0, 0, 0];
            return function() {
                var width = this.width || 1;
                var height = this.height || 1;
                var cameraToCenterDistance = 0.5 / Math.tan(this._fov / 2) * height;
                scale(m, this.projMatrix, minusY);
                translate(m, m, set$2(arr, 0, 0, -cameraToCenterDistance));

                if (this._pitch) {
                    rotateX(m, m, this._pitch);
                }

                if (this._angle) {
                    rotateZ(m, m, this._angle);
                }

                identity(m1);
                scale(m1, m1, set$2(arr, width / 2, -height / 2, 1));
                return multiply(this.domCssMatrix || createMat4(), m1, m);
            };
        }(),
        _getCameraWorldMatrix: function() {
            var q = {};
            return function() {
                var targetZ = this.getGLZoom();
                var size = this.getSize(),
                    scale$$1 = this.getGLScale();

                var center2D = this._prjToPoint(this._prjCenter, targetZ);

                this.cameraLookAt = set$2(this.cameraLookAt || [0, 0, 0], center2D.x, center2D.y, 0);
                var pitch = this.getPitch() * RADIAN$1;
                var bearing = this.getBearing() * RADIAN$1;

                var ratio = this._getFovRatio();

                var z = scale$$1 * (size.height || 1) / 2 / ratio;
                var cz = z * Math.cos(pitch);
                var dist = Math.sin(pitch) * z;
                var cx = center2D.x - dist * Math.sin(bearing);
                var cy = center2D.y - dist * Math.cos(bearing);
                this.cameraPosition = set$2(this.cameraPosition || [0, 0, 0], cx, cy, cz);
                var d = dist || 1;
                var up = this.cameraUp = set$2(this.cameraUp || [0, 0, 0], Math.sin(bearing) * d, Math.cos(bearing) * d, 0);
                var m = this.cameraWorldMatrix = this.cameraWorldMatrix || createMat4();
                lookAt(m, this.cameraPosition, this.cameraLookAt, up);
                var cameraForward = this.cameraForward || [0, 0, 0];
                subtract(cameraForward, this.cameraLookAt, this.cameraPosition);
                this.cameraForward = normalize(cameraForward, cameraForward);
                matrixToQuaternion(q, m);
                quaternionToMatrix(m, q);
                setPosition(m, this.cameraPosition);
                return m;
            };
        }(),
        _getFovRatio: function _getFovRatio() {
            var fov = this.getFov();
            return Math.tan(fov / 2 * RADIAN$1);
        },
        _renderLayers: function _renderLayers() {
            if (this.isInteracting()) {
                return;
            }

            var layers = this._getLayers();

            layers.forEach(function(layer) {
                if (!layer) {
                    return;
                }

                var renderer = layer._getRenderer();

                if (renderer && renderer.setToRedraw) {
                    renderer.setToRedraw();
                }
            });
        }
    });

    function createMat4() {
        return identity(new Array(16));
    }

    Map$1.include({
        _onViewChange: function _onViewChange(view) {
            if (!this._viewHistory) {
                this._viewHistory = [];
                this._viewHistoryPointer = 0;
            }

            var old = this._getCurrentView();

            for (var i = this._viewHistory.length - 1; i >= 0; i--) {
                if (equalMapView(view, this._viewHistory[i])) {
                    this._viewHistoryPointer = i;

                    this._fireViewChange(old, view);

                    return;
                }
            }

            if (this._viewHistoryPointer < this._viewHistory.length - 1) {
                this._viewHistory.splice(this._viewHistoryPointer + 1);
            }

            this._viewHistory.push(view);

            var count = this.options['viewHistoryCount'];

            if (count > 0 && this._viewHistory.length > count) {
                this._viewHistory.splice(0, this._viewHistory.length - count);
            }

            this._viewHistoryPointer = this._viewHistory.length - 1;

            this._fireViewChange(old, view);
        },
        zoomToPreviousView: function zoomToPreviousView(options) {
            if (options === void 0) {
                options = {};
            }

            if (!this.hasPreviousView()) {
                return null;
            }

            var view = this._viewHistory[--this._viewHistoryPointer];

            this._zoomToView(view, options);

            return view;
        },
        hasPreviousView: function hasPreviousView() {
            if (!this._viewHistory || this._viewHistoryPointer === 0) {
                return false;
            }

            return true;
        },
        zoomToNextView: function zoomToNextView(options) {
            if (options === void 0) {
                options = {};
            }

            if (!this.hasNextView()) {
                return null;
            }

            var view = this._viewHistory[++this._viewHistoryPointer];

            this._zoomToView(view, options);

            return view;
        },
        hasNextView: function hasNextView() {
            if (!this._viewHistory || this._viewHistoryPointer === this._viewHistory.length - 1) {
                return false;
            }

            return true;
        },
        _zoomToView: function _zoomToView(view, options) {
            var _this = this;

            var old = this.getView();

            if (options['animation']) {
                this._animateTo(view, {
                    'duration': options['duration']
                }, function(frame) {
                    if (frame.state.playState === 'finished') {
                        _this._fireViewChange(old, view);
                    }
                });
            } else {
                this.setView(view);

                this._fireViewChange(old, view);
            }
        },
        getViewHistory: function getViewHistory() {
            return this._viewHistory;
        },
        _fireViewChange: function _fireViewChange(old, view) {
            this._fireEvent('viewchange', {
                'old': old,
                'new': view
            });
        },
        _getCurrentView: function _getCurrentView() {
            if (!this._viewHistory) {
                return null;
            }

            return this._viewHistory[this._viewHistoryPointer];
        }
    });
    Map$1.mergeOptions({
        'viewHistory': true,
        'viewHistoryCount': 10
    });

    var options$h = {
        'mode': 'LineString',
        'language': 'zh-CN',
        'metric': true,
        'imperial': false,
        'symbol': {
            'lineColor': '#000',
            'lineWidth': 3,
            'lineOpacity': 1
        },
        'vertexSymbol': {
            'markerType': 'ellipse',
            'markerFill': '#fff',
            'markerLineColor': '#000',
            'markerLineWidth': 3,
            'markerWidth': 11,
            'markerHeight': 11
        },
        'labelOptions': {
            'textSymbol': {
                'textFaceName': 'monospace',
                'textLineSpacing': 1,
                'textHorizontalAlignment': 'right',
                'textDx': 15
            },
            'boxStyle': {
                'padding': [6, 2],
                'symbol': {
                    'markerType': 'square',
                    'markerFill': '#fff',
                    'markerFillOpacity': 0.9,
                    'markerLineColor': '#b4b3b3'
                }
            }
        },
        'clearButtonSymbol': [{
            'markerType': 'square',
            'markerFill': '#fff',
            'markerLineColor': '#b4b3b3',
            'markerLineWidth': 2,
            'markerWidth': 15,
            'markerHeight': 15,
            'markerDx': 20
        }, {
            'markerType': 'x',
            'markerWidth': 10,
            'markerHeight': 10,
            'markerDx': 20
        }]
    };

    var DistanceTool = function(_DrawTool) {
        _inheritsLoose(DistanceTool, _DrawTool);

        function DistanceTool(options) {
            var _this;

            _this = _DrawTool.call(this, options) || this;

            _this.on('enable', _this._afterEnable, _assertThisInitialized(_assertThisInitialized(_this))).on('disable', _this._afterDisable, _assertThisInitialized(_assertThisInitialized(_this)));

            _this._measureLayers = [];
            return _this;
        }

        var _proto = DistanceTool.prototype;

        _proto.clear = function clear() {
            if (isArrayHasData(this._measureLayers)) {
                for (var i = 0; i < this._measureLayers.length; i++) {
                    this._measureLayers[i].remove();
                }
            }

            delete this._lastMeasure;
            delete this._lastVertex;
            this._measureLayers = [];
            return this;
        };

        _proto.getMeasureLayers = function getMeasureLayers() {
            return this._measureLayers;
        };

        _proto.getLastMeasure = function getLastMeasure() {
            if (!this._lastMeasure) {
                return 0;
            }

            return this._lastMeasure;
        };

        _proto.undo = function undo() {
            _DrawTool.prototype.undo.call(this);

            var pointer = this._historyPointer;

            if (pointer !== this._vertexes.length) {
                for (var i = pointer; i < this._vertexes.length; i++) {
                    if (this._vertexes[i].label) {
                        this._vertexes[i].label.remove();
                    }

                    this._vertexes[i].marker.remove();
                }
            }

            return this;
        };

        _proto.redo = function redo() {
            _DrawTool.prototype.redo.call(this);

            var i = this._historyPointer - 1;

            if (this._vertexes[i]) {
                if (!this._vertexes[i].marker.getLayer()) {
                    if (this._vertexes[i].label) {
                        this._vertexes[i].label.addTo(this._measureMarkerLayer);
                    }

                    this._vertexes[i].marker.addTo(this._measureMarkerLayer);
                }
            }

            return this;
        };

        _proto._measure = function _measure(toMeasure) {
            var map = this.getMap();
            var length;

            if (toMeasure instanceof Geometry) {
                length = map.computeGeometryLength(toMeasure);
            } else if (Array.isArray(toMeasure)) {
                length = map.getProjection().measureLength(toMeasure);
            }

            this._lastMeasure = length;
            var units;

            if (this.options['language'] === 'zh-CN') {
                units = [' 米', ' 公里', ' 英尺', ' 英里'];
            } else {
                units = [' m', ' km', ' feet', ' mile'];
            }

            var content = '';

            if (this.options['metric']) {
                content += length < 1000 ? length.toFixed(0) + units[0] : (length / 1000).toFixed(2) + units[1];
            }

            if (this.options['imperial']) {
                length *= 3.2808399;

                if (content.length > 0) {
                    content += '\n';
                }

                content += length < 5280 ? length.toFixed(0) + units[2] : (length / 5280).toFixed(2) + units[3];
            }

            return content;
        };

        _proto._registerMeasureEvents = function _registerMeasureEvents() {
            this.on('drawstart', this._msOnDrawStart, this).on('drawvertex', this._msOnDrawVertex, this).on('mousemove', this._msOnMouseMove, this).on('drawend', this._msOnDrawEnd, this);
        };

        _proto._afterEnable = function _afterEnable() {
            this._registerMeasureEvents();
        };

        _proto._afterDisable = function _afterDisable() {
            this.off('drawstart', this._msOnDrawStart, this).off('drawvertex', this._msOnDrawVertex, this).off('mousemove', this._msOnMouseMove, this).off('drawend', this._msOnDrawEnd, this);
        };

        _proto._msOnDrawStart = function _msOnDrawStart(param) {
            var map = this.getMap();

            var prjCoord = map._pointToPrj(param['point2d']);

            var uid = UID();
            var layerId = 'distancetool_' + uid;
            var markerLayerId = 'distancetool_markers_' + uid;

            if (!map.getLayer(layerId)) {
                this._measureLineLayer = new VectorLayer(layerId).addTo(map);
                this._measureMarkerLayer = new VectorLayer(markerLayerId).addTo(map);
            } else {
                this._measureLineLayer = map.getLayer(layerId);
                this._measureMarkerLayer = map.getLayer(markerLayerId);
            }

            this._measureLayers.push(this._measureLineLayer);

            this._measureLayers.push(this._measureMarkerLayer);

            var marker = new Marker(param['coordinate'], {
                'symbol': this.options['vertexSymbol']
            });

            marker._setPrjCoordinates(prjCoord);

            var content = this.options['language'] === 'zh-CN' ? '起点' : 'start';
            var startLabel = new Label(content, param['coordinate'], this.options['labelOptions']);

            startLabel._setPrjCoordinates(prjCoord);

            this._lastVertex = startLabel;

            this._addVertexMarker(marker, startLabel);
        };

        _proto._msOnMouseMove = function _msOnMouseMove(param) {
            var ms = this._measure(this._msGetCoordsToMeasure(param));

            if (!this._tailMarker) {
                var symbol = extendSymbol(this.options['vertexSymbol']);
                symbol['markerWidth'] /= 2;
                symbol['markerHeight'] /= 2;
                this._tailMarker = new Marker(param['coordinate'], {
                    'symbol': symbol
                }).addTo(this._measureMarkerLayer);
                this._tailLabel = new Label(ms, param['coordinate'], this.options['labelOptions']).addTo(this._measureMarkerLayer);
            }

            var prjCoords = this._geometry._getPrjCoordinates();

            var lastCoord = prjCoords[prjCoords.length - 1];

            this._tailMarker.setCoordinates(param['coordinate']);

            this._tailMarker._setPrjCoordinates(lastCoord);

            this._tailLabel.setContent(ms);

            this._tailLabel.setCoordinates(param['coordinate']);

            this._tailLabel._setPrjCoordinates(lastCoord);
        };

        _proto._msGetCoordsToMeasure = function _msGetCoordsToMeasure(param) {
            return param['geometry'].getCoordinates().concat([param['coordinate']]);
        };

        _proto._msOnDrawVertex = function _msOnDrawVertex(param) {
            var prjCoords = this._geometry._getPrjCoordinates();

            var lastCoord = prjCoords[prjCoords.length - 1];
            var geometry = param['geometry'];
            var marker = new Marker(param['coordinate'], {
                'symbol': this.options['vertexSymbol']
            });

            var length = this._measure(geometry);

            var vertexLabel = new Label(length, param['coordinate'], this.options['labelOptions']);

            this._addVertexMarker(marker, vertexLabel);

            vertexLabel._setPrjCoordinates(lastCoord);

            marker._setPrjCoordinates(lastCoord);

            this._lastVertex = vertexLabel;
        };

        _proto._addVertexMarker = function _addVertexMarker(marker, vertexLabel) {
            if (!this._vertexes) {
                this._vertexes = [];
            }

            this._vertexes.push({
                label: vertexLabel,
                marker: marker
            });

            if (this._historyPointer !== undefined) {
                this._vertexes.length = this._historyPointer;
            }

            this._measureMarkerLayer.addGeometry(marker);

            if (vertexLabel) {
                this._measureMarkerLayer.addGeometry(vertexLabel);
            }
        };

        _proto._msOnDrawEnd = function _msOnDrawEnd(param) {
            this._clearTailMarker();

            var size = this._lastVertex.getSize();

            if (!size) {
                size = new Size(10, 10);
            }

            this._addClearMarker(this._lastVertex.getCoordinates(), this._lastVertex._getPrjCoordinates(), size['width']);

            var geo = param['geometry'].copy();

            geo._setPrjCoordinates(param['geometry']._getPrjCoordinates());

            geo.addTo(this._measureLineLayer);
            this._lastMeasure = geo.getLength();
        };

        _proto._addClearMarker = function _addClearMarker(coordinates, prjCoord, dx) {
            var symbol = this.options['clearButtonSymbol'];
            var dxSymbol = {
                'markerDx': (symbol['markerDx'] || 0) + dx,
                'textDx': (symbol['textDx'] || 0) + dx
            };

            if (Array.isArray(symbol)) {
                dxSymbol = symbol.map(function(s) {
                    if (s) {
                        return {
                            'markerDx': (s['markerDx'] || 0) + dx,
                            'textDx': (s['textDx'] || 0) + dx
                        };
                    }

                    return null;
                });
            }

            symbol = extendSymbol(symbol, dxSymbol);
            var endMarker = new Marker(coordinates, {
                'symbol': symbol
            });
            var measureLineLayer = this._measureLineLayer,
                measureMarkerLayer = this._measureMarkerLayer;
            endMarker.on('click', function() {
                measureLineLayer.remove();
                measureMarkerLayer.remove();
                return false;
            }, this);
            endMarker.addTo(this._measureMarkerLayer);

            endMarker._setPrjCoordinates(prjCoord);
        };

        _proto._clearTailMarker = function _clearTailMarker() {
            if (this._tailMarker) {
                this._tailMarker.remove();

                delete this._tailMarker;
            }

            if (this._tailLabel) {
                this._tailLabel.remove();

                delete this._tailLabel;
            }
        };

        return DistanceTool;
    }(DrawTool);

    DistanceTool.mergeOptions(options$h);

    var options$i = {
        'mode': 'Polygon',
        'symbol': {
            'lineColor': '#000000',
            'lineWidth': 2,
            'lineOpacity': 1,
            'lineDasharray': '',
            'polygonFill': '#ffffff',
            'polygonOpacity': 0.5
        }
    };

    var AreaTool = function(_DistanceTool) {
        _inheritsLoose(AreaTool, _DistanceTool);

        function AreaTool(options) {
            var _this;

            _this = _DistanceTool.call(this, options) || this;

            _this.on('enable', _this._afterEnable, _assertThisInitialized(_assertThisInitialized(_this))).on('disable', _this._afterDisable, _assertThisInitialized(_assertThisInitialized(_this)));

            _this._measureLayers = [];
            return _this;
        }

        var _proto = AreaTool.prototype;

        _proto._measure = function _measure(toMeasure) {
            var map = this.getMap();
            var area;

            if (toMeasure instanceof Geometry) {
                area = map.computeGeometryArea(toMeasure);
            } else if (Array.isArray(toMeasure)) {
                area = map.getProjection().measureArea(toMeasure);
            }

            this._lastMeasure = area;
            var units;

            if (this.options['language'] === 'zh-CN') {
                units = [' 平方米', ' 平方公里', ' 平方英尺', ' 平方英里'];
            } else {
                units = [' sq.m', ' sq.km', ' sq.ft', ' sq.mi'];
            }

            var content = '';

            if (this.options['metric']) {
                content += area < 1E6 ? area.toFixed(0) + units[0] : (area / 1E6).toFixed(2) + units[1];
            }

            if (this.options['imperial']) {
                area *= 3.2808399;

                if (content.length > 0) {
                    content += '\n';
                }

                var sqmi = 5280 * 5280;
                content += area < sqmi ? area.toFixed(0) + units[2] : (area / sqmi).toFixed(2) + units[3];
            }

            return content;
        };

        _proto._msGetCoordsToMeasure = function _msGetCoordsToMeasure(param) {
            return param['geometry'].getShell().concat([param['coordinate']]);
        };

        _proto._msOnDrawVertex = function _msOnDrawVertex(param) {
            var prjCoord = this.getMap()._pointToPrj(param['point2d']);

            var vertexMarker = new Marker(param['coordinate'], {
                'symbol': this.options['vertexSymbol']
            });

            vertexMarker._setPrjCoordinates(prjCoord);

            this._measure(param['geometry']);

            this._lastVertex = vertexMarker;

            this._addVertexMarker(vertexMarker);
        };

        _proto._msOnDrawEnd = function _msOnDrawEnd(param) {
            this._clearTailMarker();

            var prjCoord = this.getMap()._pointToPrj(param['point2d']);

            var ms = this._measure(param['geometry']);

            var endLabel = new Label(ms, param['coordinate'], this.options['labelOptions']).addTo(this._measureMarkerLayer);

            endLabel._setPrjCoordinates(prjCoord);

            var size = endLabel.getSize();

            if (!size) {
                size = new Size(10, 10);
            }

            this._addClearMarker(param['coordinate'], prjCoord, size['width']);

            var geo = param['geometry'].copy();

            geo._setPrjCoordinates(param['geometry']._getPrjCoordinates());

            geo.addTo(this._measureLineLayer);
            this._lastMeasure = geo.getArea();
        };

        return AreaTool;
    }(DistanceTool);

    AreaTool.mergeOptions(options$i);

    var circleHooks = {
        'create': function create(projection, prjCoord) {
            var center = projection.unproject(prjCoord[0]);
            var circle = new Circle(center, 0);

            circle._setPrjCoordinates(prjCoord[0]);

            return circle;
        },
        'update': function update(projection, prjPath, geometry) {
            var map = geometry.getMap();
            var prjCoord = Array.isArray(prjPath) ? prjPath[prjPath.length - 1] : prjPath;
            var nextCoord = projection.unproject(prjCoord);
            var radius = map.computeLength(geometry.getCenter(), nextCoord);
            geometry.setRadius(radius);
        },
        'generate': function generate(geometry) {
            return geometry;
        }
    };
    DrawTool.registerMode('circle', extend({
        'clickLimit': 2,
        'action': ['click', 'mousemove', 'click']
    }, circleHooks));
    DrawTool.registerMode('freeHandCircle', extend({
        'action': ['mousedown', 'mousemove', 'mouseup']
    }, circleHooks));
    var ellipseHooks = {
        'create': function create(projection, prjCoord) {
            var center = projection.unproject(prjCoord[0]);
            var ellipse = new Ellipse(center, 0, 0);

            ellipse._setPrjCoordinates(prjCoord[0]);

            return ellipse;
        },
        'update': function update(projection, prjPath, geometry) {
            var map = geometry.getMap();
            var center = geometry.getCenter();
            var prjCoord = Array.isArray(prjPath) ? prjPath[prjPath.length - 1] : prjPath;
            var nextCoord = projection.unproject(prjCoord);
            var rx = map.computeLength(center, new Coordinate({
                x: nextCoord.x,
                y: center.y
            }));
            var ry = map.computeLength(center, new Coordinate({
                x: center.x,
                y: nextCoord.y
            }));
            geometry.setWidth(rx * 2);
            geometry.setHeight(ry * 2);
        },
        'generate': function generate(geometry) {
            return geometry;
        }
    };
    DrawTool.registerMode('ellipse', extend({
        'clickLimit': 2,
        'action': ['click', 'mousemove', 'click']
    }, ellipseHooks));
    DrawTool.registerMode('freeHandEllipse', extend({
        'action': ['mousedown', 'mousemove', 'mouseup']
    }, ellipseHooks));
    var rectangleHooks = {
        'create': function create(projection, prjCoords) {
            var rect = new Polygon([]);
            rect._firstClick = prjCoords[0];
            return rect;
        },
        'update': function update(projection, prjCoords, geometry, param) {
            var map = geometry.getMap();
            var containerPoint = param['containerPoint'];

            var firstClick = map._prjToContainerPoint(geometry._firstClick);

            var ring = [
                [firstClick.x, firstClick.y],
                [containerPoint.x, firstClick.y],
                [containerPoint.x, containerPoint.y],
                [firstClick.x, containerPoint.y]
            ];
            geometry.setCoordinates(ring.map(function(c) {
                return map.containerPointToCoord(new Point(c));
            }));

            geometry._setPrjCoordinates(ring.map(function(c) {
                return map._containerPointToPrj(new Point(c));
            }));
        },
        'generate': function generate(geometry) {
            return geometry;
        }
    };
    DrawTool.registerMode('rectangle', extend({
        'clickLimit': 2,
        'action': ['click', 'mousemove', 'click']
    }, rectangleHooks));
    DrawTool.registerMode('freeHandRectangle', extend({
        'action': ['mousedown', 'mousemove', 'mouseup']
    }, rectangleHooks));
    DrawTool.registerMode('point', {
        'clickLimit': 1,
        'action': ['click'],
        'create': function create(projection, prjCoord) {
            var center = projection.unproject(prjCoord[0]);
            var marker = new Marker(center);

            marker._setPrjCoordinates(prjCoord[0]);

            return marker;
        },
        'generate': function generate(geometry) {
            return geometry;
        }
    });
    var polygonHooks = {
        'create': function create(projection, prjPath) {
            var path = prjPath.map(function(c) {
                return projection.unproject(c);
            });
            var line = new LineString(path);

            line._setPrjCoordinates(prjPath);

            return line;
        },
        'update': function update(projection, path, geometry) {
            var symbol = geometry.getSymbol();
            var prjCoords;

            if (Array.isArray(path)) {
                prjCoords = path;
            } else {
                prjCoords = geometry._getPrjCoordinates();
                prjCoords.push(path);
            }

            var coordinates = prjCoords.map(function(c) {
                return projection.unproject(c);
            });
            geometry.setCoordinates(coordinates);

            geometry._setPrjCoordinates(prjCoords);

            var layer = geometry.getLayer();

            if (layer) {
                var polygon = layer.getGeometryById('polygon');

                if (!polygon && prjCoords.length >= 3) {
                    polygon = new Polygon([coordinates], {
                        'id': 'polygon'
                    });

                    if (symbol) {
                        var pSymbol = extendSymbol(symbol, {
                            'lineOpacity': 0
                        });
                        polygon.setSymbol(pSymbol);
                    }

                    polygon.addTo(layer);
                }

                if (polygon) {
                    polygon._setPrjCoordinates(prjCoords);
                }
            }
        },
        'generate': function generate(geometry) {
            var polygon = new Polygon(geometry.getCoordinates(), {
                'symbol': geometry.getSymbol()
            });

            polygon._setPrjCoordinates(geometry._getPrjCoordinates());

            polygon._projCode = geometry._projCode;
            return polygon;
        }
    };
    DrawTool.registerMode('polygon', extend({
        'action': ['click', 'mousemove', 'dblclick']
    }, polygonHooks));
    DrawTool.registerMode('freeHandPolygon', extend({
        'action': ['mousedown', 'mousemove', 'mouseup']
    }, polygonHooks));
    var lineStringHooks = {
        'create': function create(projection, prjPath) {
            var path = prjPath.map(function(c) {
                return projection.unproject(c);
            });
            var line = new LineString(path);

            line._setPrjCoordinates(prjPath);

            return line;
        },
        'update': function update(projection, prjPath, geometry) {
            var prjCoords;

            if (Array.isArray(prjPath)) {
                prjCoords = prjPath;
            } else {
                prjCoords = geometry._getPrjCoordinates();
                prjCoords.push(prjPath);
            }

            var path = prjCoords.map(function(c) {
                return projection.unproject(c);
            });
            geometry.setCoordinates(path);

            geometry._setPrjCoordinates(prjCoords);
        },
        'generate': function generate(geometry) {
            return geometry;
        }
    };
    DrawTool.registerMode('linestring', extend({
        'action': ['click', 'mousemove', 'dblclick']
    }, lineStringHooks));
    DrawTool.registerMode('freeHandLinestring', extend({
        'action': ['mousedown', 'mousemove', 'mouseup']
    }, lineStringHooks));
    DrawTool.registerMode('arccurve', {
        'action': ['click', 'mousemove', 'dblclick'],
        'create': function create(projection, prjPath) {
            var path = prjPath.map(function(c) {
                return projection.unproject(c);
            });
            var arc = new ArcCurve(path);

            arc._setPrjCoordinates(prjPath);

            return arc;
        },
        'update': lineStringHooks.update,
        'generate': function generate(geometry) {
            return geometry;
        }
    });
    DrawTool.registerMode('quadbeziercurve', {
        'action': ['click', 'mousemove', 'dblclick'],
        'create': function create(projection, prjPath) {
            var path = prjPath.map(function(c) {
                return projection.unproject(c);
            });
            var curve = new QuadBezierCurve(path);

            curve._setPrjCoordinates(prjPath);

            return curve;
        },
        'update': lineStringHooks.update,
        'generate': function generate(geometry) {
            return geometry;
        }
    });
    DrawTool.registerMode('cubicbeziercurve', {
        'action': ['click', 'mousemove', 'dblclick'],
        'create': function create(projection, prjPath) {
            var path = prjPath.map(function(c) {
                return projection.unproject(c);
            });
            var curve = new CubicBezierCurve(path);

            curve._setPrjCoordinates(prjPath);

            return curve;
        },
        'update': lineStringHooks.update,
        'generate': function generate(geometry) {
            return geometry;
        }
    });
    DrawTool.registerMode('boxZoom', {
        'action': ['mousedown', 'mousemove', 'mouseup'],
        'create': function create(projection, prjCoord) {
            prjCoord = prjCoord[0];
            var center = projection.unproject(prjCoord);
            var marker = new Marker(center);
            marker._firstClick = prjCoord;
            return marker;
        },
        'update': function update(projection, prjCoord, geometry, param) {
            var map = geometry.getMap();

            var p1 = map._prjToContainerPoint(geometry._firstClick),
                p2 = param['containerPoint'];

            prjCoord = map._containerPointToPrj(new Coordinate(Math.min(p1.x, p2.x), Math.min(p1.y, p2.y)));
            var center = projection.unproject(prjCoord);

            geometry.setCoordinates(center)._setPrjCoordinates(prjCoord);

            geometry.updateSymbol({
                markerWidth: Math.abs(p1.x - p2.x),
                markerHeight: Math.abs(p1.y - p2.y)
            });
        },
        'generate': function generate(geometry) {
            return geometry;
        }
    });

    function parse(arcConf) {
        var tileInfo = arcConf['tileInfo'],
            tileSize = [tileInfo['cols'], tileInfo['rows']],
            resolutions = [],
            lods = tileInfo['lods'];

        for (var i = 0, len = lods.length; i < len; i++) {
            resolutions.push(lods[i]['resolution']);
        }

        var fullExtent = arcConf['fullExtent'],
            origin = tileInfo['origin'],
            tileSystem = [1, -1, origin['x'], origin['y']];
        delete fullExtent['spatialReference'];
        return {
            'spatialReference': {
                'resolutions': resolutions,
                'fullExtent': fullExtent
            },
            'tileSystem': tileSystem,
            'tileSize': tileSize
        };
    }

    SpatialReference.loadArcgis = function(url, cb, options) {
        if (options === void 0) {
            options = {
                'jsonp': true
            };
        }

        if (isString(url) && url.substring(0, 1) !== '{') {
            Ajax.getJSON(url, function(err, json) {
                if (err) {
                    cb(err);
                    return;
                }

                var spatialRef = parse(json);
                cb(null, spatialRef);
            }, options);
        } else {
            if (isString(url)) {
                url = parseJSON(url);
            }

            var spatialRef = parse(url);
            cb(null, spatialRef);
        }

        return this;
    };

    function getProjection(projection) {
        var prj = projection.indexOf('EPSG') > -1 ? projection : 'EPSG:' + projection;
        prj = strReplace(prj, [
            ['4490', '4326'],
            ['102100', '3857'],
            ['900913', '3857']
        ]);
        return prj;
    }

    function strReplace(str, repArray) {
        if (repArray === void 0) {
            repArray = [];
        }

        repArray.forEach(function(rep) {
            var template = rep[0],
                value = rep[1];
            str = str.replace(template, value);
        });
        return str;
    }

    function parseWMTSXML(str, requestUrl, options) {
        var parser = new DOMParser();
        var xmlDoc = parser.parseFromString(str, 'text/xml');
        var content = xmlDoc.querySelectorAll('Contents')[0];

        if (!content) {
            return [];
        }

        var layers = content.getElementsByTagName('Layer');

        if (!layers.length) {
            return [];
        }

        var TileMatrixSets = [];

        for (var i = 0, len = content.childNodes.length; i < len; i++) {
            if (content.childNodes[i].nodeName === 'TileMatrixSet') {
                TileMatrixSets.push(content.childNodes[i]);
            }
        }

        if (!TileMatrixSets.length) {
            return [];
        }

        var result = [];

        for (var _i = 0, _len = layers.length; _i < _len; _i++) {
            var layer = layers[_i];
            var style = layer.querySelectorAll('Style')[0];

            if (style) {
                style = style.getElementsByTagName('ows:Identifier')[0];

                if (style) {
                    style = style.textContent;
                }
            }

            var layerName = layer.getElementsByTagName('ows:Identifier')[0];

            if (layerName) {
                layerName = layerName.textContent;
            }

            var resourceURL = layer.querySelectorAll('ResourceURL')[0];
            var url = '';

            if (resourceURL) {
                url = resourceURL.attributes.template.value;
            }

            var _parseTileMatrixSet = parseTileMatrixSet(TileMatrixSets, _i, options),
                resolutions = _parseTileMatrixSet.resolutions,
                tileSize = _parseTileMatrixSet.tileSize,
                tileSystem = _parseTileMatrixSet.tileSystem,
                projection = _parseTileMatrixSet.projection,
                TileMatrixSet = _parseTileMatrixSet.TileMatrixSet;

            if (!url.length) {
                url = requestUrl.substr(0, requestUrl.lastIndexOf('?'));
                url += '?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER={LAYER}&STYLE={Style}&TILEMATRIXSET={TileMatrixSet}&FORMAT=tiles&TILEMATRIX={TileMatrix}&TILEROW={TileRow}&TILECOL={TileCol}';
            }

            var urlTemplate = strReplace(url, [
                ['{LAYER}', layerName],
                ['{Layer}', layerName],
                ['{layer}', layerName],
                ['{STYLE}', style],
                ['{Style}', style],
                ['{style}', style],
                ['{TileMatrixSet}', TileMatrixSet],
                ['{TileMatrix}', '{z}'],
                ['{TileRow}', '{y}'],
                ['{TileCol}', '{x}']
            ]);
            result.push({
                tileSize: tileSize,
                tileSystem: tileSystem,
                spatialReference: {
                    resolutions: resolutions,
                    projection: projection
                },
                urlTemplate: urlTemplate,
                info: {
                    layerName: layerName,
                    TileMatrixSet: TileMatrixSet,
                    style: style,
                    tileSize: tileSize,
                    tileSystem: tileSystem,
                    resolutions: resolutions,
                    projection: projection,
                    urlTemplate: urlTemplate
                }
            });
        }

        return result;
    }

    function parseTileMatrixSet(TileMatrixSets, index, options) {
        if (options === void 0) {
            options = {};
        }

        var TileMatrixSet = TileMatrixSets[index];
        var TileMatrixs = TileMatrixSet.getElementsByTagName('TileMatrix');
        var resolutions = [],
            tileSystem = [],
            tileSize = [];
        var projection, tset;

        if (!projection) {
            var supportedCRS = TileMatrixSet.getElementsByTagName('ows:SupportedCRS')[0];

            if (supportedCRS) {
                projection = supportedCRS.textContent;
                projection = projection.split('EPSG')[1];

                while (projection.indexOf(':') > -1) {
                    projection = projection.replace(':', '');
                }

                projection = getProjection(projection);
            }
        }

        if (!tset) {
            tset = TileMatrixSet.getElementsByTagName('ows:Identifier')[0];

            if (tset) {
                tset = tset.textContent;
            }
        }

        var transformValue = 0.0002645833333333333;

        if (options.isArcgis) {
            transformValue = 0.00028;
        }

        if (projection && projection.indexOf('4326') > -1) {
            transformValue = 2.3767925226029154e-9;

            if (options.isArcgis) {
                transformValue = 2.518101729011901e-9;
            }
        }

        var minLevel = Infinity;

        for (var _index = 0; _index < TileMatrixs.length; _index++) {
            var TileMatrix = TileMatrixs[_index];
            var level = TileMatrix.getElementsByTagName('ows:Identifier')[0].textContent;
            level = parseInt(level);
            minLevel = Math.min(minLevel, level);
            var ScaleDenominator = TileMatrix.getElementsByTagName('ScaleDenominator')[0].textContent;
            var TopLeftCorner = TileMatrix.getElementsByTagName('TopLeftCorner')[0].textContent;
            var TileWidth = TileMatrix.getElementsByTagName('TileWidth')[0].textContent;
            var TileHeight = TileMatrix.getElementsByTagName('TileHeight')[0].textContent;

            if (tileSize.length === 0) {
                tileSize.push(parseInt(TileWidth), parseInt(TileHeight));
            }

            if (tileSystem.length === 0) {
                var _TopLeftCorner$split$ = TopLeftCorner.split(' ').filter(function(s) {
                        return s !== '';
                    }).map(function(v) {
                        return parseFloat(v);
                    }),
                    x = _TopLeftCorner$split$[0],
                    y = _TopLeftCorner$split$[1];

                if (x > 0) {
                    tileSystem.push(1, -1, y, x);
                } else {
                    tileSystem.push(1, -1, x, y);
                }
            }

            var res = parseFloat(ScaleDenominator) * transformValue;
            resolutions.push(res);
        }

        if (minLevel > 0) {
            var _res = resolutions[0];

            for (var i = minLevel - 1; i >= 0; i--) {
                _res = _res * 2;
                resolutions.splice(0, 0, _res);
            }
        }

        return {
            resolutions: resolutions,
            tileSize: tileSize,
            tileSystem: tileSystem,
            projection: projection,
            TileMatrixSet: tset
        };
    }

    SpatialReference.loadWMTS = function(url, cb, options) {
        if (options === void 0) {
            options = {
                'jsonp': true
            };
        }

        if (isString(url)) {
            Ajax.get(url, function(err, xml) {
                if (err) {
                    cb(err);
                    return;
                }

                var layers = parseWMTSXML(xml, url, options);
                cb(null, layers);
            }, options);
        }

        return this;
    };

    var options$j = {
        'eventsPropagation': false,
        'eventsToStop': null,
        'dx': 0,
        'dy': 0,
        'autoPan': false,
        'autoPanDuration': 600,
        'single': true,
        'animation': 'scale',
        'animationOnHide': true,
        'animationDuration': 500,
        'pitchWithMap': false,
        'rotateWithMap': false
    };

    var UIComponent = function(_Eventable) {
        _inheritsLoose(UIComponent, _Eventable);

        function UIComponent(options) {
            return _Eventable.call(this, options) || this;
        }

        var _proto = UIComponent.prototype;

        _proto.addTo = function addTo(owner) {
            this._owner = owner;

            this._switchEvents('on');

            if (this.onAdd) {
                this.onAdd();
            }

            this.fire('add');
            return this;
        };

        _proto.getMap = function getMap() {
            if (!this._owner) {
                return null;
            }

            if (this._owner.getBaseLayer) {
                return this._owner;
            }

            return this._owner.getMap();
        };

        _proto.show = function show(coordinate) {
            var map = this.getMap();

            if (!map) {
                return this;
            }

            if (!this._mapEventsOn) {
                this._switchMapEvents('on');
            }

            coordinate = coordinate || this._coordinate || this._owner.getCenter();
            var visible = this.isVisible();
            this.fire('showstart');

            var container = this._getUIContainer();

            this._coordinate = coordinate;

            this._removePrevDOM();

            var dom = this.__uiDOM = this.buildOn(map);
            dom['eventsPropagation'] = this.options['eventsPropagation'];

            if (!dom) {
                this.fire('showend');
                return this;
            }

            this._measureSize(dom);

            if (this._singleton()) {
                map[this._uiDomKey()] = dom;
            }

            this._setPosition();

            dom.style[TRANSITION] = null;
            container.appendChild(dom);

            var anim = this._getAnimation();

            if (visible) {
                anim.ok = false;
            }

            if (anim.ok) {
                if (anim.fade) {
                    dom.style.opacity = 0;
                }

                if (anim.scale) {
                    if (this.getTransformOrigin) {
                        var origin = this.getTransformOrigin();
                        dom.style[TRANSFORMORIGIN] = origin;
                    }

                    dom.style[TRANSFORM] = this._toCSSTranslate(this._pos) + ' scale(0)';
                }
            }

            dom.style.display = '';

            if (this.options['eventsToStop']) {
                on(dom, this.options['eventsToStop'], stopPropagation);
            }

            if (this.options['autoPan']) {
                this._autoPan();
            }

            var transition = anim.transition;

            if (anim.ok && transition) {
                dom.offsetHeight;

                if (transition) {
                    dom.style[TRANSITION] = transition;
                }

                if (anim.fade) {
                    dom.style.opacity = 1;
                }

                if (anim.scale) {
                    dom.style[TRANSFORM] = this._toCSSTranslate(this._pos) + ' scale(1)';
                }
            }

            this.fire('showend');
            return this;
        };

        _proto.hide = function hide() {
            var _this = this;

            if (!this.getDOM() || !this.getMap()) {
                return this;
            }

            var anim = this._getAnimation(),
                dom = this.getDOM();

            if (!this.options['animationOnHide']) {
                anim.ok = false;
            }

            if (!anim.ok) {
                dom.style.display = 'none';
                this.fire('hide');
            } else {
                dom.offsetHeight;
                dom.style[TRANSITION] = anim.transition;
                setTimeout(function() {
                    dom.style.display = 'none';

                    _this.fire('hide');
                }, this.options['animationDuration']);
            }

            if (anim.fade) {
                dom.style.opacity = 0;
            }

            if (anim.scale) {
                dom.style[TRANSFORM] = this._toCSSTranslate(this._pos) + ' scale(0)';
            }

            return this;
        };

        _proto.isVisible = function isVisible() {
            var dom = this.getDOM();
            return this.getMap() && dom && dom.parentNode && dom.style.display !== 'none';
        };

        _proto.remove = function remove() {
            delete this._mapEventsOn;

            if (!this._owner) {
                return this;
            }

            this.hide();

            this._switchEvents('off');

            if (this.onRemove) {
                this.onRemove();
            }

            if (!this._singleton() && this.__uiDOM) {
                this._removePrevDOM();
            }

            delete this._owner;
            this.fire('remove');
            return this;
        };

        _proto.getSize = function getSize() {
            if (this._size) {
                return this._size.copy();
            } else {
                return null;
            }
        };

        _proto.getOwner = function getOwner() {
            return this._owner;
        };

        _proto.getDOM = function getDOM() {
            return this.__uiDOM;
        };

        _proto.getPosition = function getPosition() {
            if (!this.getMap()) {
                return null;
            }

            var p = this._getViewPoint()._round();

            if (this.getOffset) {
                var o = this.getOffset()._round();

                if (o) {
                    p._add(o);
                }
            }

            return p;
        };

        _proto._getAnimation = function _getAnimation() {
            var anim = {
                'fade': false,
                'scale': false
            };
            var animations = this.options['animation'] ? this.options['animation'].split(',') : [];

            for (var i = 0; i < animations.length; i++) {
                var trimed = trim(animations[i]);

                if (trimed === 'fade') {
                    anim.fade = true;
                } else if (trimed === 'scale') {
                    anim.scale = true;
                }
            }

            var transition = null;

            if (anim.fade) {
                transition = 'opacity ' + this.options['animationDuration'] + 'ms';
            }

            if (anim.scale) {
                transition = transition ? transition + ',' : '';
                transition += TRANSFORM + ' ' + this.options['animationDuration'] + 'ms';
            }

            anim.transition = transition;
            anim.ok = transition !== null;
            return anim;
        };

        _proto._getViewPoint = function _getViewPoint() {
            var alt = 0;

            if (this._owner && this._owner.getAltitude) {
                var altitude = this._owner.getAltitude();

                if (altitude > 0) {
                    alt = this._meterToPoint(this._coordinate, altitude);
                }
            }

            return this.getMap().coordToViewPoint(this._coordinate, undefined, alt)._add(this.options['dx'], this.options['dy']);
        };

        _proto._meterToPoint = function _meterToPoint(center, altitude) {
            var map = this.getMap();
            return map.distanceToPoint(altitude, 0, undefined, center).x * sign(altitude);
        };

        _proto._autoPan = function _autoPan() {
            var map = this.getMap(),
                dom = this.getDOM();

            if (map.isMoving()) {
                return;
            }

            var point = this._pos;
            var mapSize = map.getSize(),
                mapWidth = mapSize['width'],
                mapHeight = mapSize['height'];
            var containerPoint = map.viewPointToContainerPoint(point);
            var clientWidth = parseInt(dom.clientWidth),
                clientHeight = parseInt(dom.clientHeight);
            var left = 0,
                top = 0;

            if (containerPoint.x < 0) {
                left = -(containerPoint.x - clientWidth / 2);
            } else if (containerPoint.x + clientWidth - 35 > mapWidth) {
                left = mapWidth - (containerPoint.x + clientWidth * 3 / 2);
            }

            if (containerPoint.y - clientHeight < 0) {
                top = -(containerPoint.y - clientHeight) + 50;
            } else if (containerPoint.y > mapHeight) {
                top = mapHeight - containerPoint.y - clientHeight - 30;
            }

            if (top !== 0 || left !== 0) {
                map.panBy(new Point(left, top), {
                    'duration': this.options['autoPanDuration']
                });
            }
        };

        _proto._measureSize = function _measureSize(dom) {
            var container = this._getUIContainer();

            dom.style.position = 'absolute';
            dom.style.left = -99999 + 'px';
            var anchor = dom.style.bottom ? 'bottom' : 'top';
            dom.style[anchor] = -99999 + 'px';
            dom.style.display = '';
            container.appendChild(dom);
            this._size = new Size(dom.clientWidth, dom.clientHeight);
            dom.style.display = 'none';
            dom.style.left = '0px';
            dom.style[anchor] = '0px';
            return this._size;
        };

        _proto._removePrevDOM = function _removePrevDOM() {
            if (this.onDomRemove) {
                this.onDomRemove();
            }

            var eventsToStop = this.options['eventsToStop'];

            if (this._singleton()) {
                var map = this.getMap(),
                    key = this._uiDomKey();

                if (map[key]) {
                    if (eventsToStop) {
                        off(map[key], eventsToStop, stopPropagation);
                    }

                    removeDomNode(map[key]);
                    delete map[key];
                }

                delete this.__uiDOM;
            } else if (this.__uiDOM) {
                if (eventsToStop) {
                    off(this.__uiDOM, eventsToStop, stopPropagation);
                }

                removeDomNode(this.__uiDOM);
                delete this.__uiDOM;
            }
        };

        _proto._uiDomKey = function _uiDomKey() {
            return '__ui_' + this._getClassName();
        };

        _proto._singleton = function _singleton() {
            return this.options['single'];
        };

        _proto._getUIContainer = function _getUIContainer() {
            return this.getMap()._panels['ui'];
        };

        _proto._getClassName = function _getClassName() {
            return 'UIComponent';
        };

        _proto._switchMapEvents = function _switchMapEvents(to) {
            var map = this.getMap();

            if (!map) {
                return;
            }

            this._mapEventsOn = to === 'on';

            var events = this._getDefaultEvents();

            if (this.getEvents) {
                extend(events, this.getEvents());
            }

            if (events) {
                for (var p in events) {
                    if (events.hasOwnProperty(p)) {
                        map[to](p, events[p], this);
                    }
                }
            }
        };

        _proto._switchEvents = function _switchEvents(to) {
            this._switchMapEvents(to);

            var ownerEvents = this._getOwnerEvents();

            if (this._owner) {
                for (var p in ownerEvents) {
                    if (ownerEvents.hasOwnProperty(p)) {
                        this._owner[to](p, ownerEvents[p], this);
                    }
                }
            }
        };

        _proto._getDefaultEvents = function _getDefaultEvents() {
            return {
                'zooming rotate pitch': this.onEvent,
                'zoomend': this.onZoomEnd,
                'moving': this.onMoving,
                'resize': this.onResize
            };
        };

        _proto._getOwnerEvents = function _getOwnerEvents() {
            var events = {};

            if (this._owner && this._owner instanceof Geometry) {
                events.positionchange = this.onGeometryPositionChange;
            }

            if (this.getOwnerEvents) {
                extend(events, this.getOwnerEvents());
            }

            return events;
        };

        _proto.onGeometryPositionChange = function onGeometryPositionChange(param) {
            if (this._owner && this.isVisible()) {
                this.show(param['target'].getCenter());
            }
        };

        _proto.onMoving = function onMoving() {
            if (this.isVisible() && this.getMap().isTransforming()) {
                this._updatePosition();
            }
        };

        _proto.onEvent = function onEvent() {
            if (this.isVisible()) {
                this._updatePosition();
            }
        };

        _proto.onZoomEnd = function onZoomEnd() {
            if (this.isVisible()) {
                this._setPosition();
            }
        };

        _proto.onResize = function onResize() {
            if (this.isVisible()) {
                this._setPosition();
            }
        };

        _proto._updatePosition = function _updatePosition() {
            var renderer = this.getMap()._getRenderer();

            renderer.callInNextFrame(this._setPosition.bind(this));
        };

        _proto._setPosition = function _setPosition() {
            var dom = this.getDOM();
            if (!dom) return;
            dom.style[TRANSITION] = null;
            var p = this.getPosition();
            this._pos = p;
            dom.style[TRANSFORM] = this._toCSSTranslate(p) + ' scale(1)';
        };

        _proto._toCSSTranslate = function _toCSSTranslate(p) {
            if (!p) {
                return '';
            }

            if (Browser$1.any3d) {
                var map = this.getMap(),
                    bearing = map ? map.getBearing() : 0,
                    pitch = map ? map.getPitch() : 0;
                var r = '';

                if (this.options['pitchWithMap'] && pitch) {
                    r += " rotateX(" + Math.round(pitch) + "deg)";
                }

                if (this.options['rotateWithMap'] && bearing) {
                    r += " rotateZ(" + Math.round(-bearing) + "deg)";
                }

                return 'translate3d(' + p.x + 'px,' + p.y + 'px, 0px)' + r;
            } else {
                return 'translate(' + p.x + 'px,' + p.y + 'px)';
            }
        };

        UIComponent.isSupport = function isSupport(owner) {
            if (owner && isFunction(owner.on) && isFunction(owner.off) && isFunction(owner.getCenter)) {
                return true;
            }

            return false;
        };

        return UIComponent;
    }(Eventable(Class));

    UIComponent.mergeOptions(options$j);

    var options$k = {
        'containerClass': null,
        'eventsPropagation': true,
        'draggable': false,
        'single': false,
        'content': null
    };
    var domEvents = 'mousedown ' + 'mouseup ' + 'mouseenter ' + 'mouseover ' + 'mouseout ' + 'mousemove ' + 'click ' + 'dblclick ' + 'contextmenu ' + 'keypress ' + 'touchstart ' + 'touchmove ' + 'touchend';

    var UIMarker = function(_Handlerable) {
        _inheritsLoose(UIMarker, _Handlerable);

        function UIMarker(coordinate, options) {
            var _this;

            _this = _Handlerable.call(this, options) || this;
            _this._markerCoord = new Coordinate(coordinate);
            return _this;
        }

        var _proto = UIMarker.prototype;

        _proto._getClassName = function _getClassName() {
            return 'UIMarker';
        };

        _proto.setCoordinates = function setCoordinates(coordinates) {
            this._markerCoord = coordinates;
            this.fire('positionchange');

            if (this.isVisible()) {
                this._coordinate = this._markerCoord;

                this._setPosition();
            }

            return this;
        };

        _proto.getCoordinates = function getCoordinates() {
            return this._markerCoord;
        };

        _proto.setContent = function setContent(content) {
            var old = this.options['content'];
            this.options['content'] = content;
            this.fire('contentchange', {
                'old': old,
                'new': content
            });

            if (this.isVisible()) {
                this.show();
            }

            return this;
        };

        _proto.getContent = function getContent() {
            return this.options['content'];
        };

        _proto.onAdd = function onAdd() {
            this.show();
        };

        _proto.show = function show() {
            return _Handlerable.prototype.show.call(this, this._markerCoord);
        };

        _proto.flash = function flash$$1(interval, count, cb, context) {
            return flash.call(this, interval, count, cb, context);
        };

        _proto.buildOn = function buildOn() {
            var dom;

            if (isString(this.options['content'])) {
                dom = createEl('div');
                dom.innerHTML = this.options['content'];
            } else {
                dom = this.options['content'];
            }

            if (this.options['containerClass']) {
                dom.className = this.options['containerClass'];
            }

            this._registerDOMEvents(dom);

            return dom;
        };

        _proto.getOffset = function getOffset() {
            var size = this.getSize();
            return new Point(-size.width / 2, -size.height / 2);
        };

        _proto.getTransformOrigin = function getTransformOrigin() {
            return 'center center';
        };

        _proto.onDomRemove = function onDomRemove() {
            var dom = this.getDOM();

            this._removeDOMEvents(dom);
        };

        _proto.isDragging = function isDragging() {
            if (this['draggable']) {
                return this['draggable'].isDragging();
            }

            return false;
        };

        _proto._registerDOMEvents = function _registerDOMEvents(dom) {
            on(dom, domEvents, this._onDomEvents, this);
        };

        _proto._onDomEvents = function _onDomEvents(e) {
            var event = this.getMap()._parseEvent(e, e.type);

            this.fire(e.type, event);
        };

        _proto._removeDOMEvents = function _removeDOMEvents(dom) {
            off(dom, domEvents, this._onDomEvents, this);
        };

        _proto._getConnectPoints = function _getConnectPoints() {
            var map = this.getMap();
            var containerPoint = map.coordToContainerPoint(this.getCoordinates());
            var size = this.getSize(),
                width = size.width,
                height = size.height;
            var anchors = [map.containerPointToCoordinate(containerPoint.add(-width / 2, 0)), map.containerPointToCoordinate(containerPoint.add(width / 2, 0)), map.containerPointToCoordinate(containerPoint.add(0, height / 2)), map.containerPointToCoordinate(containerPoint.add(0, -height / 2))];
            return anchors;
        };

        return UIMarker;
    }(Handlerable(UIComponent));

    UIMarker.mergeOptions(options$k);
    var EVENTS$1 = Browser$1.touch ? 'touchstart mousedown' : 'mousedown';

    var UIMarkerDragHandler = function(_Handler) {
        _inheritsLoose(UIMarkerDragHandler, _Handler);

        function UIMarkerDragHandler(target) {
            return _Handler.call(this, target) || this;
        }

        var _proto2 = UIMarkerDragHandler.prototype;

        _proto2.addHooks = function addHooks() {
            this.target.on(EVENTS$1, this._startDrag, this);
        };

        _proto2.removeHooks = function removeHooks() {
            this.target.off(EVENTS$1, this._startDrag, this);
        };

        _proto2._startDrag = function _startDrag(param) {
            var domEvent = param['domEvent'];

            if (domEvent.touches && domEvent.touches.length > 1 || domEvent.button === 2) {
                return;
            }

            if (this.isDragging()) {
                return;
            }

            this.target.on('click', this._endDrag, this);
            this._lastCoord = param['coordinate'];
            this._lastPoint = param['containerPoint'];

            this._prepareDragHandler();

            this._dragHandler.onMouseDown(param['domEvent']);

            this.target.fire('dragstart', param);
        };

        _proto2._prepareDragHandler = function _prepareDragHandler() {
            this._dragHandler = new DragHandler(this.target.getDOM(), {
                'cancelOn': this._cancelOn.bind(this),
                'ignoreMouseleave': true
            });

            this._dragHandler.on('mousedown', this._onMouseDown, this);

            this._dragHandler.on('dragging', this._dragging, this);

            this._dragHandler.on('mouseup', this._endDrag, this);

            this._dragHandler.enable();
        };

        _proto2._cancelOn = function _cancelOn(domEvent) {
            var target = domEvent.srcElement || domEvent.target,
                tagName = target.tagName.toLowerCase();

            if (tagName === 'button' || tagName === 'input' || tagName === 'select' || tagName === 'option' || tagName === 'textarea') {
                return true;
            }

            return false;
        };

        _proto2._onMouseDown = function _onMouseDown(param) {
            stopPropagation(param['domEvent']);
        };

        _proto2._dragging = function _dragging(param) {
            var target = this.target,
                map = target.getMap(),
                eventParam = map._parseEvent(param['domEvent']),
                domEvent = eventParam['domEvent'];

            if (domEvent.touches && domEvent.touches.length > 1) {
                return;
            }

            if (!this._isDragging) {
                this._isDragging = true;
                return;
            }

            var coord = eventParam['coordinate'],
                point = eventParam['containerPoint'];

            if (!this._lastCoord) {
                this._lastCoord = coord;
            }

            if (!this._lastPoint) {
                this._lastPoint = point;
            }

            var coordOffset = coord.sub(this._lastCoord),
                pointOffset = point.sub(this._lastPoint);
            this._lastCoord = coord;
            this._lastPoint = point;
            this.target.setCoordinates(this.target.getCoordinates().add(coordOffset));
            eventParam['coordOffset'] = coordOffset;
            eventParam['pointOffset'] = pointOffset;
            target.fire('dragging', eventParam);
        };

        _proto2._endDrag = function _endDrag(param) {
            var target = this.target,
                map = target.getMap();

            if (this._dragHandler) {
                target.off('click', this._endDrag, this);

                this._dragHandler.disable();

                delete this._dragHandler;
            }

            delete this._lastCoord;
            delete this._lastPoint;
            this._isDragging = false;

            if (!map) {
                return;
            }

            var eventParam = map._parseEvent(param['domEvent']);

            target.fire('dragend', eventParam);
        };

        _proto2.isDragging = function isDragging() {
            if (!this._isDragging) {
                return false;
            }

            return true;
        };

        return UIMarkerDragHandler;
    }(Handler$1);

    UIMarker.addInitHook('addHandler', 'draggable', UIMarkerDragHandler);

    var options$l = {
        'containerClass': 'maptalks-msgBox',
        'autoPan': true,
        'autoCloseOn': null,
        'autoOpenOn': 'click',
        'width': 300,
        'minHeight': 120,
        'custom': false,
        'title': null,
        'content': null
    };

    var InfoWindow = function(_UIComponent) {
        _inheritsLoose(InfoWindow, _UIComponent);

        function InfoWindow() {
            return _UIComponent.apply(this, arguments) || this;
        }

        var _proto = InfoWindow.prototype;

        _proto._getClassName = function _getClassName() {
            return 'InfoWindow';
        };

        _proto.addTo = function addTo(owner) {
            if (owner instanceof Geometry) {
                if (owner.getInfoWindow() && owner.getInfoWindow() !== this) {
                    owner.removeInfoWindow();
                }

                owner._infoWindow = this;
            }

            return _UIComponent.prototype.addTo.call(this, owner);
        };

        _proto.setContent = function setContent(content) {
            var old = this.options['content'];
            this.options['content'] = content;
            this.fire('contentchange', {
                'old': old,
                'new': content
            });

            if (this.isVisible()) {
                this.show(this._coordinate);
            }

            return this;
        };

        _proto.getContent = function getContent() {
            return this.options['content'];
        };

        _proto.setTitle = function setTitle(title) {
            var old = title;
            this.options['title'] = title;
            this.fire('contentchange', {
                'old': old,
                'new': title
            });

            if (this.isVisible()) {
                this.show(this._coordinate);
            }

            return this;
        };

        _proto.getTitle = function getTitle() {
            return this.options['title'];
        };

        _proto.buildOn = function buildOn() {
            if (this.options['custom']) {
                if (isString(this.options['content'])) {
                    var _dom = createEl('div');

                    _dom.innerHTML = this.options['content'];
                    return _dom;
                } else {
                    return this.options['content'];
                }
            }

            var dom = createEl('div');

            if (this.options['containerClass']) {
                dom.className = this.options['containerClass'];
            }

            dom.style.width = this._getWindowWidth() + 'px';
            dom.style.bottom = '0px';
            var content = '<em class="maptalks-ico"></em>';

            if (this.options['title']) {
                content += '<h2>' + this.options['title'] + '</h2>';
            }

            content += '<a href="javascript:void(0);" class="maptalks-close"></a><div class="maptalks-msgContent"></div>';
            dom.innerHTML = content;
            var msgContent = dom.querySelector('.maptalks-msgContent');

            if (isString(this.options['content'])) {
                msgContent.innerHTML = this.options['content'];
            } else {
                msgContent.appendChild(this.options['content']);
            }

            this._onCloseBtnClick = this.hide.bind(this);
            var closeBtn = dom.querySelector('.maptalks-close');
            addDomEvent(closeBtn, 'click touchend', this._onCloseBtnClick);
            return dom;
        };

        _proto.getTransformOrigin = function getTransformOrigin() {
            var size = this.getSize();
            return size.width / 2 + 'px bottom';
        };

        _proto.getOffset = function getOffset() {
            var size = this.getSize();
            var o = new Point(-size['width'] / 2, 0);

            if (!this.options['custom']) {
                o._sub(4, 12);
            } else {
                o._sub(0, size['height']);
            }

            var owner = this.getOwner();

            if (owner instanceof Marker || owner instanceof MultiPoint) {
                var painter, markerSize;

                if (owner instanceof Marker) {
                    painter = owner._getPainter();
                    markerSize = owner.getSize();
                } else {
                    var children = owner.getGeometries();

                    if (!children || !children.length) {
                        return o;
                    }

                    painter = children[0]._getPainter();
                    markerSize = children[0].getSize();
                }

                if (painter) {
                    var fixExtent = painter.getFixedExtent();

                    o._add(fixExtent.xmax - markerSize.width / 2, fixExtent.ymin);
                } else {
                    o._add(0, -markerSize.height);
                }
            }

            return o;
        };

        _proto.show = function show(coordinate) {
            if (!this.getMap()) {
                return this;
            }

            if (!this.getMap().options['enableInfoWindow']) {
                return this;
            }

            return _UIComponent.prototype.show.call(this, coordinate);
        };

        _proto.getEvents = function getEvents() {
            if (!this.options['autoCloseOn']) {
                return null;
            }

            var events = {};
            events[this.options['autoCloseOn']] = this.hide;
            return events;
        };

        _proto.getOwnerEvents = function getOwnerEvents() {
            var owner = this.getOwner();

            if (!this.options['autoOpenOn'] || !owner) {
                return null;
            }

            var events = {};
            events[this.options['autoOpenOn']] = this._onAutoOpen;
            return events;
        };

        _proto.onRemove = function onRemove() {
            this.onDomRemove();
        };

        _proto.onDomRemove = function onDomRemove() {
            if (this._onCloseBtnClick) {
                var dom = this.getDOM();
                var closeBtn = dom.childNodes[2];
                removeDomEvent(closeBtn, 'click touchend', this._onCloseBtnClick);
                delete this._onCloseBtnClick;
            }
        };

        _proto._onAutoOpen = function _onAutoOpen(e) {
            var _this = this;

            var owner = this.getOwner();
            setTimeout(function() {
                if (owner instanceof Marker || owner instanceof UIComponent) {
                    _this.show(owner.getCoordinates());
                } else if (owner instanceof MultiPoint) {
                    _this.show(owner.findClosest(e.coordinate));
                } else if (owner instanceof LineString || owner instanceof MultiLineString) {
                    if (_this.getMap().getScale() >= 8) {
                        e.coordinate = _this._rectifyMouseCoordinte(owner, e.coordinate);
                    }

                    _this.show(e.coordinate);
                } else {
                    _this.show(e.coordinate);
                }
            }, 1);
        };

        _proto._rectifyMouseCoordinte = function _rectifyMouseCoordinte(owner, mouseCoordinate) {
            var _this2 = this;

            if (owner instanceof LineString) {
                return this._rectifyLineStringMouseCoordinate(owner, mouseCoordinate).coordinate;
            } else if (owner instanceof MultiLineString) {
                return owner.getGeometries().map(function(lineString) {
                    return _this2._rectifyLineStringMouseCoordinate(lineString, mouseCoordinate);
                }).sort(function(a, b) {
                    return a.dis - b.dis;
                })[0].coordinate;
            }

            return mouseCoordinate;
        };

        _proto._rectifyLineStringMouseCoordinate = function _rectifyLineStringMouseCoordinate(lineString, mouseCoordinate) {
            var _this3 = this;

            var pts = lineString.getCoordinates().map(function(coordinate) {
                return _this3.getMap().coordToContainerPoint(coordinate);
            });
            var mousePt = this.getMap().coordToContainerPoint(mouseCoordinate);
            var minDis = Infinity,
                coordinateIndex = -1;

            for (var i = 0, len = pts.length; i < len; i++) {
                var pt = pts[i];
                var dis = mousePt.distanceTo(pt);

                if (dis < minDis) {
                    minDis = dis;
                    coordinateIndex = i;
                }
            }

            var filterPts = [];

            if (coordinateIndex === 0) {
                filterPts.push(pts[0], pts[1]);
            } else if (coordinateIndex === pts.length - 1) {
                filterPts.push(pts[coordinateIndex - 1], pts[coordinateIndex]);
            } else {
                filterPts.push(pts[coordinateIndex - 1], pts[coordinateIndex], pts[coordinateIndex + 1]);
            }

            var xys = [];

            var _this$getMap$getSize = this.getMap().getSize(),
                width = _this$getMap$getSize.width,
                height = _this$getMap$getSize.height;

            for (var _i = 0, _len = filterPts.length - 1; _i < _len; _i++) {
                var pt1 = filterPts[_i],
                    pt2 = filterPts[_i + 1];

                if (pt1.x === pt2.x) {
                    var miny = Math.max(0, Math.min(pt1.y, pt2.y));
                    var maxy = Math.min(height, Math.max(pt1.y, pt2.y));

                    for (var y = miny; y <= maxy; y++) {
                        xys.push(new Point(pt1.x, y));
                    }
                } else {
                    var k = (pt2.y - pt1.y) / (pt2.x - pt1.x);
                    var minx = Math.max(0, Math.min(pt1.x, pt2.x));
                    var maxx = Math.min(width, Math.max(pt1.x, pt2.x));

                    for (var x = minx; x <= maxx; x++) {
                        var _y = k * (x - pt1.x) + pt1.y;

                        xys.push(new Point(x, _y));
                    }
                }
            }

            var minPtDis = Infinity,
                ptIndex = -1;

            for (var _i2 = 0, _len2 = xys.length; _i2 < _len2; _i2++) {
                var _pt = xys[_i2];

                var _dis = mousePt.distanceTo(_pt);

                if (_dis < minPtDis) {
                    minPtDis = _dis;
                    ptIndex = _i2;
                }
            }

            return {
                dis: minPtDis,
                coordinate: ptIndex < 0 ? mouseCoordinate : this.getMap().containerPointToCoord(xys[ptIndex])
            };
        };

        _proto._getWindowWidth = function _getWindowWidth() {
            var defaultWidth = 300;
            var width = this.options['width'];

            if (!width) {
                width = defaultWidth;
            }

            return width;
        };

        return InfoWindow;
    }(UIComponent);

    InfoWindow.mergeOptions(options$l);

    var options$m = {
        'width': 0,
        'height': 0,
        'animation': 'fade',
        'containerClass': 'maptalks-tooltip',
        'showTimeout': 400
    };

    var ToolTip = function(_UIComponent) {
        _inheritsLoose(ToolTip, _UIComponent);

        var _proto = ToolTip.prototype;

        _proto._getClassName = function _getClassName() {
            return 'ToolTip';
        };

        function ToolTip(content, options) {
            var _this;

            if (options === void 0) {
                options = {};
            }

            _this = _UIComponent.call(this, options) || this;
            _this._content = content;
            return _this;
        }

        _proto.addTo = function addTo(owner) {
            if (ToolTip.isSupport(owner)) {
                owner.on('mousemove', this.onMouseMove, this);
                owner.on('mouseout', this.onMouseOut, this);
                return _UIComponent.prototype.addTo.call(this, owner);
            } else {
                throw new Error('Invalid geometry or UIMarker the tooltip is added to.');
            }
        };

        _proto.setStyle = function setStyle$$1(cssName) {
            this.options.containerClass = cssName;
            return this;
        };

        _proto.getStyle = function getStyle() {
            return this.options.containerClass;
        };

        _proto.getContent = function getContent() {
            return this._content;
        };

        _proto.buildOn = function buildOn() {
            var dom = createEl('div');
            var options = this.options || {};

            if (options.height) {
                dom.style.height = options.height + 'px';
            }

            if (options.width) {
                dom.style.width = options.width + 'px';
            }

            var cssName = options.containerClass || options.cssName;

            if (!cssName && options.height) {
                dom.style.lineHeight = options.height + 'px';
            }

            dom.innerHTML = "<div class=\"" + cssName + "\">" + this._content + "</div>";
            return dom;
        };

        _proto.onMouseOut = function onMouseOut() {
            clearTimeout(this._timeout);

            if (this.isVisible()) {
                this._removePrevDOM();
            }
        };

        _proto.onMouseMove = function onMouseMove(e) {
            var _this2 = this;

            clearTimeout(this._timeout);
            var map = this.getMap();

            if (!map) {
                return;
            }

            var coord = map.locateByPoint(e.coordinate, -5, 25);

            if (this.options['showTimeout'] === 0) {
                this.show(coord);
            } else {
                this._timeout = setTimeout(function() {
                    if (map) {
                        _this2.show(coord);
                    }
                }, this.options['showTimeout']);
            }
        };

        _proto.onRemove = function onRemove() {
            clearTimeout(this._timeout);

            if (this._owner) {
                this._owner.off('mouseover', this.onMouseOver, this);

                this._owner.off('mouseout', this.onMouseOut, this);
            }
        };

        _proto._getViewPoint = function _getViewPoint() {
            return this.getMap().coordToViewPoint(this._coordinate, undefined, 0)._add(this.options['dx'], this.options['dy']);
        };

        return ToolTip;
    }(UIComponent);

    ToolTip.mergeOptions(options$m);

    var defaultOptions = {
        'containerClass': 'maptalks-menu',
        'animation': null,
        'animationDelay': 10,
        'animationOnHide': false,
        'autoPan': false,
        'width': 160,
        'maxHeight': 0,
        'custom': false,
        'items': []
    };

    var Menu = function(_UIComponent) {
        _inheritsLoose(Menu, _UIComponent);

        function Menu(options) {
            return _UIComponent.call(this, options) || this;
        }

        var _proto = Menu.prototype;

        _proto._getClassName = function _getClassName() {
            return 'Menu';
        };

        _proto.addTo = function addTo(owner) {
            if (owner._menu && owner._menu !== this) {
                owner.removeMenu();
            }

            owner._menu = this;
            return UIComponent.prototype.addTo.apply(this, arguments);
        };

        _proto.setItems = function setItems(items) {
            this.options['items'] = items;
            return this;
        };

        _proto.getItems = function getItems() {
            return this.options['items'] || [];
        };

        _proto.buildOn = function buildOn() {
            if (this.options['custom']) {
                if (isString(this.options['items'])) {
                    var container = createEl('div');
                    container.innerHTML = this.options['items'];
                    return container;
                } else {
                    return this.options['items'];
                }
            } else {
                var dom = createEl('div');

                if (this.options['containerClass']) {
                    addClass(dom, this.options['containerClass']);
                }

                dom.style.width = this._getMenuWidth() + 'px';

                var menuItems = this._createMenuItemDom();

                dom.appendChild(menuItems);
                on(dom, 'contextmenu', preventDefault);
                return dom;
            }
        };

        _proto.getOffset = function getOffset() {
            if (!this.getMap()) {
                return null;
            }

            var mapSize = this.getMap().getSize(),
                p = this.getMap().viewPointToContainerPoint(this._getViewPoint()),
                size = this.getSize();
            var dx = 0,
                dy = 0;

            if (p.x + size['width'] > mapSize['width']) {
                dx = -size['width'];
            }

            if (p.y + size['height'] > mapSize['height']) {
                dy = -size['height'];
            }

            return new Point(dx, dy);
        };

        _proto.getTransformOrigin = function getTransformOrigin() {
            var p = this.getOffset()._multi(-1);

            return p.x + 'px ' + p.y + 'px';
        };

        _proto.getEvents = function getEvents() {
            return {
                '_zoomstart _zoomend _movestart _dblclick _click': this._removePrevDOM
            };
        };

        _proto._createMenuItemDom = function _createMenuItemDom() {
            var me = this;
            var map = this.getMap();
            var ul = createEl('ul');
            addClass(ul, 'maptalks-menu-items');
            var items = this.getItems();

            function onMenuClick(index) {
                return function(e) {
                    var param = map._parseEvent(e, 'click');

                    param['target'] = me;
                    param['owner'] = me._owner;
                    param['index'] = index;

                    var result = this._callback(param);

                    if (result === false) {
                        return;
                    }

                    me.hide();
                };
            }

            var item, itemDOM;

            for (var i = 0, len = items.length; i < len; i++) {
                item = items[i];

                if (item === '-' || item === '_') {
                    itemDOM = createEl('li');
                    addClass(itemDOM, 'maptalks-menu-splitter');
                } else {
                    itemDOM = createEl('li');
                    var itemTitle = item['item'];

                    if (isFunction(itemTitle)) {
                        itemTitle = itemTitle({
                            'owner': this._owner,
                            'index': i
                        });
                    }

                    itemDOM.innerHTML = itemTitle;
                    itemDOM._callback = item['click'];
                    on(itemDOM, 'click', onMenuClick(i));
                }

                ul.appendChild(itemDOM);
            }

            var maxHeight = this.options['maxHeight'] || 0;

            if (maxHeight > 0) {
                setStyle(ul, 'max-height: ' + maxHeight + 'px; overflow-y: auto;');
            }

            return ul;
        };

        _proto._getMenuWidth = function _getMenuWidth() {
            var defaultWidth = 160;
            var width = this.options['width'] || defaultWidth;
            return width;
        };

        return Menu;
    }(UIComponent);

    Menu.mergeOptions(defaultOptions);

    var Menuable = {
        setMenu: function setMenu(options) {
            this._menuOptions = options;

            if (this._menu) {
                this._menu.setOptions(options);
            } else {
                this.on('contextmenu', this._defaultOpenMenu, this);
            }

            return this;
        },
        openMenu: function openMenu(coordinate) {
            var map = this instanceof Map$1 ? this : this.getMap();

            if (!coordinate) {
                coordinate = this.getCenter();
            }

            if (!this._menu) {
                if (this._menuOptions && map) {
                    this._bindMenu(this._menuOptions);

                    this._menu.show(coordinate);
                }
            } else {
                this._menu.show(coordinate);
            }

            return this;
        },
        setMenuItems: function setMenuItems(items) {
            if (!this._menuOptions) {
                this._menuOptions = {};
            }

            if (Array.isArray(items)) {
                this._menuOptions['custom'] = false;
            }

            this._menuOptions['items'] = items;
            this.setMenu(this._menuOptions);
            return this;
        },
        getMenuItems: function getMenuItems() {
            if (this._menu) {
                return this._menu.getItems();
            } else if (this._menuOptions) {
                return this._menuOptions['items'] || [];
            }

            return [];
        },
        closeMenu: function closeMenu() {
            if (this._menu) {
                this._menu.hide();
            }

            return this;
        },
        removeMenu: function removeMenu() {
            this.off('contextmenu', this._defaultOpenMenu, this);

            this._unbindMenu();

            delete this._menuOptions;
            return this;
        },
        _bindMenu: function _bindMenu(options) {
            this._menu = new Menu(options);

            this._menu.addTo(this);

            return this;
        },
        _unbindMenu: function _unbindMenu() {
            if (this._menu) {
                this.closeMenu();

                this._menu.remove();

                delete this._menu;
            }

            return this;
        },
        _defaultOpenMenu: function _defaultOpenMenu(param) {
            if (this.listens('contextmenu') > 1) {
                return true;
            } else {
                this.openMenu(param['coordinate']);
                return false;
            }
        }
    };
    Map$1.include(Menuable);
    Geometry.include(Menuable);



    var index$4 = /*#__PURE__*/ Object.freeze({
        UIComponent: UIComponent,
        UIMarker: UIMarker,
        InfoWindow: InfoWindow,
        ToolTip: ToolTip,
        Menuable: Menuable,
        Menu: Menu
    });

    var Control = function(_Eventable) {
        _inheritsLoose(Control, _Eventable);

        function Control(options) {
            if (options && options['position'] && !isString(options['position'])) {
                options['position'] = extend({}, options['position']);
            }

            return _Eventable.call(this, options) || this;
        }

        var _proto = Control.prototype;

        _proto.addTo = function addTo(map) {
            this.remove();

            if (!map.options['control']) {
                return this;
            }

            this._map = map;
            var controlContainer = map._panels.control;
            this.__ctrlContainer = createEl('div');
            setStyle(this.__ctrlContainer, 'position:absolute;overflow:visible;');
            this.update();
            controlContainer.appendChild(this.__ctrlContainer);

            if (this.onAdd) {
                this.onAdd();
            }

            this.fire('add', {
                'dom': controlContainer
            });
            return this;
        };

        _proto.update = function update() {
            this.__ctrlContainer.innerHTML = '';
            this._controlDom = this.buildOn(this.getMap());

            if (this._controlDom) {
                this._updatePosition();

                this.__ctrlContainer.appendChild(this._controlDom);
            }

            return this;
        };

        _proto.getMap = function getMap() {
            return this._map;
        };

        _proto.getPosition = function getPosition() {
            return extend({}, this._parse(this.options['position']));
        };

        _proto.setPosition = function setPosition(position) {
            if (isString(position)) {
                this.options['position'] = position;
            } else {
                this.options['position'] = extend({}, position);
            }

            this._updatePosition();

            return this;
        };

        _proto.getContainerPoint = function getContainerPoint() {
            var position = this.getPosition();
            var size = this.getMap().getSize();
            var x, y;

            if (!isNil(position['left'])) {
                x = parseInt(position['left']);
            } else if (!isNil(position['right'])) {
                x = size['width'] - parseInt(position['right']);
            }

            if (!isNil(position['top'])) {
                y = parseInt(position['top']);
            } else if (!isNil(position['bottom'])) {
                y = size['height'] - parseInt(position['bottom']);
            }

            return new Point(x, y);
        };

        _proto.getContainer = function getContainer() {
            return this.__ctrlContainer;
        };

        _proto.getDOM = function getDOM() {
            return this._controlDom;
        };

        _proto.show = function show() {
            this.__ctrlContainer.style.display = '';
            return this;
        };

        _proto.hide = function hide() {
            this.__ctrlContainer.style.display = 'none';
            return this;
        };

        _proto.isVisible = function isVisible() {
            return this.__ctrlContainer && this.__ctrlContainer.style.display === '';
        };

        _proto.remove = function remove() {
            if (!this._map) {
                return this;
            }

            removeDomNode(this.__ctrlContainer);

            if (this.onRemove) {
                this.onRemove();
            }

            delete this._map;
            delete this.__ctrlContainer;
            delete this._controlDom;
            this.fire('remove');
            return this;
        };

        _proto._parse = function _parse(position) {
            var p = position;

            if (isString(position)) {
                p = Control['positions'][p];
            }

            return p;
        };

        _proto._updatePosition = function _updatePosition() {
            var position = this.getPosition();

            if (!position) {
                position = {
                    'top': 20,
                    'left': 20
                };
            }

            for (var p in position) {
                if (position.hasOwnProperty(p)) {
                    position[p] = parseInt(position[p]);
                    this.__ctrlContainer.style[p] = position[p] + 'px';
                }
            }

            this.fire('positionchange', {
                'position': extend({}, position)
            });
        };

        return Control;
    }(Eventable(Class));

    Control.positions = {
        'top-left': {
            'top': 20,
            'left': 20
        },
        'top-right': {
            'top': 20,
            'right': 20
        },
        'bottom-left': {
            'bottom': 20,
            'left': 20
        },
        'bottom-right': {
            'bottom': 20,
            'right': 20
        }
    };
    Map$1.mergeOptions({
        'control': true
    });
    Map$1.include({
        addControl: function addControl(control) {
            if (this._containerDOM.getContext) {
                return this;
            }

            control.addTo(this);
            return this;
        },
        removeControl: function removeControl(control) {
            if (!control || control.getMap() !== this) {
                return this;
            }

            control.remove();
            return this;
        }
    });

    var options$n = {
        'position': {
            'bottom': 0,
            'left': 0
        },
        'content': '<a href="http://maptalks.org" target="_blank">maptalks</a>'
    };
    var layerEvents = 'addlayer removelayer setbaselayer baselayerremove';

    var Attribution = function(_Control) {
        _inheritsLoose(Attribution, _Control);

        function Attribution() {
            return _Control.apply(this, arguments) || this;
        }

        var _proto = Attribution.prototype;

        _proto.buildOn = function buildOn() {
            this._attributionContainer = createEl('div');
            this._attributionContainer.className = 'maptalks-attribution';

            this._update();

            return this._attributionContainer;
        };

        _proto.onAdd = function onAdd() {
            this.getMap().on(layerEvents, this._update, this);
        };

        _proto.onRemove = function onRemove() {
            this.getMap().off(layerEvents, this._update, this);
        };

        _proto._update = function _update() {
            var map = this.getMap();

            if (!map) {
                return;
            }

            var attributions = map._getLayers(function(layer) {
                return layer.options['attribution'];
            }).reverse().map(function(layer) {
                return layer.options['attribution'];
            });

            var content = this.options['content'] + (attributions.length > 0 ? ' - ' + attributions.join(', ') : '');
            this._attributionContainer.innerHTML = '<span style="padding:0px 4px">' + content + '</span>';
        };

        return Attribution;
    }(Control);

    Attribution.mergeOptions(options$n);
    Map$1.mergeOptions({
        'attribution': true
    });
    Map$1.addOnLoadHook(function() {
        var a = this.options['attribution'] || this.options['attributionControl'];

        if (a) {
            this.attributionControl = new Attribution(a);
            this.addControl(this.attributionControl);
        }
    });

    var options$o = {
        'position': 'top-right',
        'baseTitle': 'Base Layers',
        'overlayTitle': 'Layers',
        'excludeLayers': [],
        'containerClass': 'maptalks-layer-switcher'
    };

    var LayerSwitcher = function(_Control) {
        _inheritsLoose(LayerSwitcher, _Control);

        function LayerSwitcher() {
            return _Control.apply(this, arguments) || this;
        }

        var _proto = LayerSwitcher.prototype;

        _proto.buildOn = function buildOn() {
            var container = this.container = createEl('div', this.options['containerClass']),
                panel = this.panel = createEl('div', 'panel'),
                button = this.button = createEl('button');
            container.appendChild(button);
            container.appendChild(panel);
            return container;
        };

        _proto.onAdd = function onAdd() {
            on(this.button, 'mouseover', this._show, this);
            on(this.panel, 'mouseleave', this._hide, this);
            on(this.getMap(), 'click', this._hide, this);
        };

        _proto.onRemove = function onRemove() {
            if (this.panel) {
                off(this.button, 'mouseover', this._show, this);
                off(this.panel, 'mouseleave', this._hide, this);
                off(this.getMap(), 'click', this._hide, this);
                removeDomNode(this.panel);
                removeDomNode(this.button);
                delete this.panel;
                delete this.button;
                delete this.container;
            }
        };

        _proto._show = function _show() {
            if (!hasClass(this.container, 'shown')) {
                addClass(this.container, 'shown');

                this._createPanel();
            }
        };

        _proto._hide = function _hide(e) {
            if (!this.panel.contains(e.toElement || e.relatedTarget)) {
                setClass(this.container, this.options['containerClass']);
            }
        };

        _proto._createPanel = function _createPanel() {
            this.panel.innerHTML = '';
            var ul = createEl('ul');
            this.panel.appendChild(ul);

            this._renderLayers(this.getMap(), ul);
        };

        _proto._renderLayers = function _renderLayers(map, elm) {
            var base = map.getBaseLayer(),
                layers = map.getLayers(),
                len = layers.length;

            if (base) {
                var baseLayers = base.layers || [base],
                    li = createEl('li', 'group'),
                    ul = createEl('ul'),
                    label = createEl('label');
                label.innerHTML = this.options['baseTitle'];
                li.appendChild(label);

                for (var i = 0, _len = baseLayers.length; i < _len; i++) {
                    var layer = baseLayers[i];

                    if (this._isExcluded(layer)) {
                        ul.appendChild(this._renderLayer(baseLayers[i], true));
                        li.appendChild(ul);
                        elm.appendChild(li);
                    }
                }
            }

            if (len) {
                var _li = createEl('li', 'group'),
                    _ul = createEl('ul'),
                    _label = createEl('label');

                _label.innerHTML = this.options['overlayTitle'];

                _li.appendChild(_label);

                for (var _i = 0; _i < len; _i++) {
                    var _layer = layers[_i];

                    if (this._isExcluded(_layer)) {
                        _ul.appendChild(this._renderLayer(_layer));
                    }
                }

                _li.appendChild(_ul);

                elm.appendChild(_li);
            }
        };

        _proto._isExcluded = function _isExcluded(layer) {
            var id = layer.getId(),
                excludeLayers = this.options['excludeLayers'];
            return !(excludeLayers.length && excludeLayers.indexOf(id) >= 0);
        };

        _proto._renderLayer = function _renderLayer(layer, isBase) {
            var _this = this;

            var li = createEl('li', 'layer'),
                label = createEl('label'),
                input = createEl('input'),
                map = this.getMap();
            var visible = layer.options['visible'];
            layer.options['visible'] = true;
            var enabled = layer.isVisible();
            layer.options['visible'] = visible;
            li.className = 'layer';

            if (isBase) {
                input.type = 'radio';
                input.name = 'base';
            } else {
                input.type = 'checkbox';
            }

            input.checked = visible && enabled;

            if (!enabled) {
                input.setAttribute('disabled', 'disabled');
            }

            input.onchange = function(e) {
                if (e.target.type === 'radio') {
                    var baseLayer = map.getBaseLayer(),
                        baseLayers = baseLayer.layers;

                    if (baseLayers) {
                        for (var i = 0, len = baseLayers.length; i < len; i++) {
                            var _baseLayer = baseLayers[i];

                            _baseLayer[_baseLayer === layer ? 'show' : 'hide']();
                        }
                    } else if (!baseLayer.isVisible()) {
                        baseLayer.show();
                    }

                    map._fireEvent('setbaselayer');
                } else {
                    layer[e.target.checked ? 'show' : 'hide']();
                }

                _this.fire('layerchange', {
                    target: layer
                });
            };

            li.appendChild(input);
            label.innerHTML = layer.getId();
            li.appendChild(label);
            return li;
        };

        return LayerSwitcher;
    }(Control);

    LayerSwitcher.mergeOptions(options$o);
    Map$1.mergeOptions({
        'layerSwitcherControl': false
    });
    Map$1.addOnLoadHook(function() {
        if (this.options['layerSwitcherControl']) {
            this.layerSwitcherControl = new LayerSwitcher(this.options['layerSwitcherControl']);
            this.addControl(this.layerSwitcherControl);
        }
    });

    var options$p = {
        'level': 4,
        'position': {
            'right': 1,
            'bottom': 1
        },
        'size': [300, 200],
        'maximize': true,
        'symbol': {
            'lineWidth': 3,
            'lineColor': '#1bbc9b',
            'polygonFill': '#1bbc9b',
            'polygonOpacity': 0.4
        },
        'containerClass': 'maptalks-overview',
        'buttonClass': 'maptalks-overview-button'
    };

    var Overview = function(_Control) {
        _inheritsLoose(Overview, _Control);

        function Overview() {
            return _Control.apply(this, arguments) || this;
        }

        var _proto = Overview.prototype;

        _proto.buildOn = function buildOn() {
            var size = this.options['size'];

            if (!this.options['maximize']) {
                size = [0, 0];
            }

            var container = createEl('div');
            var mapContainer = this.mapContainer = createEl('div');
            mapContainer.style.width = size[0] + 'px';
            mapContainer.style.height = size[1] + 'px';
            mapContainer.className = this.options['containerClass'];
            var button = this.button = createEl('div');
            button.className = this.options['buttonClass'];
            container.appendChild(mapContainer);
            container.appendChild(button);
            return container;
        };

        _proto.onAdd = function onAdd() {
            if (this.options['maximize']) {
                this._createOverview();
            }

            this.getMap().on('resize moving zooming rotate dragrotating viewchange', this._update, this).on('setbaselayer', this._updateBaseLayer, this).on('spatialreferencechange', this._updateSpatialReference, this);
            on(this.button, 'click', this._onButtonClick, this);

            this._updateButtonText();
        };

        _proto.onRemove = function onRemove() {
            this.getMap().off('resize moving zooming rotate dragrotating viewchange', this._update, this).off('setbaselayer', this._updateBaseLayer, this).off('spatialreferencechange', this._updateSpatialReference, this);

            if (this._overview) {
                this._overview.remove();

                delete this._overview;
                delete this._perspective;
            }

            off(this.button, 'click', this._onButtonClick, this);
        };

        _proto.maxmize = function maxmize() {
            var size = this.options['size'];
            var dom = this.mapContainer;
            dom.style.width = size[0] + 'px';
            dom.style.height = size[1] + 'px';

            this._createOverview();

            return this;
        };

        _proto.minimize = function minimize() {
            if (this._overview) {
                this._overview.remove();
            }

            delete this._overview;
            delete this._perspective;
            var dom = this.mapContainer;
            dom.style.width = 0 + 'px';
            dom.style.height = 0 + 'px';
            return this;
        };

        _proto.getOverviewMap = function getOverviewMap() {
            return this._overview;
        };

        _proto._onButtonClick = function _onButtonClick() {
            if (!this._overview) {
                this.maxmize();
            } else {
                this.minimize();
            }

            this._updateButtonText();
        };

        _proto._updateButtonText = function _updateButtonText() {
            if (this._overview) {
                this.button.innerHTML = '-';
            } else {
                this.button.innerHTML = '+';
            }
        };

        _proto._createOverview = function _createOverview() {
            var map = this.getMap(),
                dom = this.mapContainer;
            var options = map.config();
            extend(options, {
                'center': map.getCenter(),
                'zoom': this._getOverviewZoom(),
                'zoomAnimationDuration': 150,
                'pitch': 0,
                'bearing': 0,
                'scrollWheelZoom': false,
                'checkSize': false,
                'doubleClickZoom': false,
                'touchZoom': false,
                'control': false,
                'draggable': false,
                'maxExtent': null
            });
            this._overview = new Map$1(dom, options);

            this._updateBaseLayer();

            this._perspective = new Polygon(this._getPerspectiveCoords(), {
                'draggable': true,
                'cursor': 'move',
                'symbol': this.options['symbol']
            }).on('dragend', this._onDragEnd, this);
            new VectorLayer('perspective_layer', this._perspective).addTo(this._overview);
            this.fire('load');
        };

        _proto._getOverviewZoom = function _getOverviewZoom() {
            var map = this.getMap(),
                zoom = map.getZoom(),
                minZoom = map.getMinZoom(),
                level = this.options['level'];

            if (level > 0) {
                for (var i = level; i > 0; i--) {
                    if (zoom - i >= minZoom) {
                        return zoom - i;
                    }
                }
            } else {
                for (var _i = level; _i < 0; _i++) {
                    if (zoom - _i >= minZoom) {
                        return zoom - _i;
                    }
                }
            }

            return zoom;
        };

        _proto._onDragEnd = function _onDragEnd() {
            var center = this._perspective.getCenter();

            this._overview.setCenter(center);

            this.getMap().panTo(center);
        };

        _proto._getPerspectiveCoords = function _getPerspectiveCoords() {
            var map = this.getMap();
            return map.getContainerExtent().toArray().map(function(c) {
                return map.containerPointToCoordinate(c);
            });
        };

        _proto._update = function _update() {
            if (!this._overview) {
                return;
            }

            computeDomPosition(this._overview._containerDOM);

            var coords = this._getPerspectiveCoords();

            this._perspective.setCoordinates(coords);

            this._overview.setCenterAndZoom(this.getMap().getCenter(), this._getOverviewZoom());
        };

        _proto._updateSpatialReference = function _updateSpatialReference() {
            if (!this._overview) {
                return;
            }

            var map = this.getMap();
            var spatialRef = map.options['spatialReference'];

            this._overview.setSpatialReference(spatialRef);
        };

        _proto._updateBaseLayer = function _updateBaseLayer() {
            if (!this._overview) {
                return;
            }

            var map = this.getMap(),
                baseLayer = map.getBaseLayer();

            if (!baseLayer) {
                this._overview.setBaseLayer(null);

                return;
            }

            var layers = baseLayer.layers;
            var showIndex = 0;

            if (layers) {
                for (var i = 0, l = layers.length; i < l; i++) {
                    var _layer = layers[i];

                    if (_layer.isVisible()) {
                        showIndex = i;
                        break;
                    }
                }
            }

            var json = baseLayer.toJSON();
            var options = null;

            if (layers) {
                options = json.layers[showIndex].options;
                options.visible = true;
            } else {
                options = json.options;
            }

            this._overview.setMinZoom(options.minZoom || null).setMaxZoom(options.maxZoom || null);

            delete options.minZoom;
            delete options.maxZoom;
            delete json.options.canvas;
            json.options.visible = true;
            json.options.renderer = 'canvas';
            var layer = Layer.fromJSON(json);

            for (var p in baseLayer) {
                if (isFunction(baseLayer[p]) && baseLayer.hasOwnProperty(p) && baseLayer[p] !== baseLayer.constructor.prototype[p]) {
                    layer[p] = baseLayer[p];
                }
            }

            this._overview.setBaseLayer(layer);
        };

        return Overview;
    }(Control);

    Overview.mergeOptions(options$p);
    Map$1.mergeOptions({
        'overviewControl': false
    });
    Map$1.addOnLoadHook(function() {
        if (this.options['overviewControl']) {
            this.overviewControl = new Overview(this.options['overviewControl']);
            this.addControl(this.overviewControl);
        }
    });

    var options$q = {
        'position': 'top-right',
        'draggable': true,
        'custom': false,
        'content': '',
        'closeButton': true
    };

    var Panel = function(_Control) {
        _inheritsLoose(Panel, _Control);

        function Panel() {
            return _Control.apply(this, arguments) || this;
        }

        var _proto = Panel.prototype;

        _proto.buildOn = function buildOn() {
            var dom;

            if (this.options['custom']) {
                if (isString(this.options['content'])) {
                    dom = createEl('div');
                    dom.innerHTML = this.options['content'];
                } else {
                    dom = this.options['content'];
                }
            } else {
                dom = createEl('div', 'maptalks-panel');

                if (this.options['closeButton']) {
                    var closeButton = createEl('a', 'maptalks-close');
                    closeButton.href = 'javascript:;';

                    closeButton.onclick = function() {
                        dom.style.display = 'none';
                    };

                    dom.appendChild(closeButton);
                }

                var panelContent = createEl('div', 'maptalks-panel-content');
                panelContent.innerHTML = this.options['content'];
                dom.appendChild(panelContent);
            }

            this.draggable = new DragHandler(dom, {
                'cancelOn': this._cancelOn.bind(this),
                'ignoreMouseleave': true
            });
            this.draggable.on('dragstart', this._onDragStart, this).on('dragging', this._onDragging, this).on('dragend', this._onDragEnd, this);

            if (this.options['draggable']) {
                this.draggable.enable();
            }

            return dom;
        };

        _proto.update = function update() {
            if (this.draggable) {
                this.draggable.disable();
                delete this.draggable;
            }

            return Control.prototype.update.call(this);
        };

        _proto.setContent = function setContent(content) {
            var old = this.options['content'];
            this.options['content'] = content;
            this.fire('contentchange', {
                'old': old,
                'new': content
            });

            if (this.isVisible()) {
                this.update();
            }

            return this;
        };

        _proto.getContent = function getContent() {
            return this.options['content'];
        };

        _proto._cancelOn = function _cancelOn(domEvent) {
            var target = domEvent.srcElement || domEvent.target,
                tagName = target.tagName.toLowerCase();

            if (tagName === 'button' || tagName === 'input' || tagName === 'select' || tagName === 'option' || tagName === 'textarea') {
                return true;
            }

            return false;
        };

        _proto._onDragStart = function _onDragStart(param) {
            this._startPos = param['mousePos'];
            this._startPosition = extend({}, this.getPosition());
            this.fire('dragstart', param);
        };

        _proto._onDragging = function _onDragging(param) {
            var pos = param['mousePos'];
            var offset = pos.sub(this._startPos);
            var startPosition = this._startPosition;
            var position = this.getPosition();

            if (!isNil(position['top'])) {
                position['top'] = parseInt(startPosition['top']) + offset.y;
            }

            if (!isNil(position['bottom'])) {
                position['bottom'] = parseInt(startPosition['bottom']) - offset.y;
            }

            if (!isNil(position['left'])) {
                position['left'] = parseInt(startPosition['left']) + offset.x;
            }

            if (!isNil(position['right'])) {
                position['right'] = parseInt(startPosition['right']) - offset.x;
            }

            this.setPosition(position);
            this.fire('dragging', param);
        };

        _proto._onDragEnd = function _onDragEnd(param) {
            delete this._startPos;
            delete this._startPosition;
            this.fire('dragend', param);
        };

        _proto._getConnectPoints = function _getConnectPoints() {
            var map = this.getMap();
            var containerPoint = this.getContainerPoint();
            var dom = this.getDOM(),
                width = parseInt(dom.clientWidth),
                height = parseInt(dom.clientHeight);
            var anchors = [map.containerPointToCoordinate(containerPoint.add(width / 2, 0)), map.containerPointToCoordinate(containerPoint.add(width, height / 2)), map.containerPointToCoordinate(containerPoint.add(width / 2, height)), map.containerPointToCoordinate(containerPoint.add(0, height / 2))];
            return anchors;
        };

        return Panel;
    }(Control);

    Panel.mergeOptions(options$q);

    var options$r = {
        'position': 'bottom-left',
        'maxWidth': 100,
        'metric': true,
        'imperial': false,
        'containerClass': null
    };

    var Scale = function(_Control) {
        _inheritsLoose(Scale, _Control);

        function Scale() {
            return _Control.apply(this, arguments) || this;
        }

        var _proto = Scale.prototype;

        _proto.buildOn = function buildOn(map) {
            this._map = map;
            this._scaleContainer = createEl('div', this.options['containerClass']);

            this._addScales();

            map.on('zoomend', this._update, this);

            if (this._map._loaded) {
                this._update();
            }

            return this._scaleContainer;
        };

        _proto.onRemove = function onRemove() {
            this.getMap().off('zoomend', this._update, this);
        };

        _proto._addScales = function _addScales() {
            var css = 'border: 2px solid #000000;border-top: none;line-height: 1.1;padding: 0px;' + 'color: #000000;font-size: 11px;text-align:center;white-space: nowrap;overflow: hidden' + ';-moz-box-sizing: content-box;box-sizing: content-box;background: #fff; background: rgba(255, 255, 255, 0);';

            if (this.options['metric']) {
                this._mScale = createElOn('div', this.options['containerClass'] ? null : css, this._scaleContainer);
            }

            if (this.options['imperial']) {
                this._iScale = createElOn('div', this.options['containerClass'] ? null : css, this._scaleContainer);
            }
        };

        _proto._update = function _update() {
            var map = this._map;
            var maxMeters = map.pixelToDistance(this.options['maxWidth'], 0);

            this._updateScales(maxMeters);
        };

        _proto._updateScales = function _updateScales(maxMeters) {
            if (this.options['metric'] && maxMeters) {
                this._updateMetric(maxMeters);
            }

            if (this.options['imperial'] && maxMeters) {
                this._updateImperial(maxMeters);
            }
        };

        _proto._updateMetric = function _updateMetric(maxMeters) {
            var meters = this._getRoundNum(maxMeters),
                label = meters < 1000 ? meters + ' m' : meters / 1000 + ' km';

            this._updateScale(this._mScale, label, meters / maxMeters);
        };

        _proto._updateImperial = function _updateImperial(maxMeters) {
            var maxFeet = maxMeters * 3.2808399;
            var maxMiles, miles, feet;

            if (maxFeet > 5280) {
                maxMiles = maxFeet / 5280;
                miles = this._getRoundNum(maxMiles);

                this._updateScale(this._iScale, miles + ' mile', miles / maxMiles);
            } else {
                feet = this._getRoundNum(maxFeet);

                this._updateScale(this._iScale, feet + ' feet', feet / maxFeet);
            }
        };

        _proto._updateScale = function _updateScale(scale, text, ratio) {
            scale['style']['width'] = Math.round(this.options['maxWidth'] * ratio) + 'px';
            scale['innerHTML'] = text;
        };

        _proto._getRoundNum = function _getRoundNum(num) {
            var pow10 = Math.pow(10, (Math.floor(num) + '').length - 1);
            var d = num / pow10;
            d = d >= 10 ? 10 : d >= 5 ? 5 : d >= 3 ? 3 : d >= 2 ? 2 : 1;
            return pow10 * d;
        };

        return Scale;
    }(Control);

    Scale.mergeOptions(options$r);
    Map$1.mergeOptions({
        'scaleControl': false
    });
    Map$1.addOnLoadHook(function() {
        if (this.options['scaleControl']) {
            this.scaleControl = new Scale(this.options['scaleControl']);
            this.addControl(this.scaleControl);
        }
    });

    var options$s = {
        'height': 28,
        'vertical': false,
        'position': 'top-right',
        'reverseMenu': false,
        'items': {}
    };

    var Toolbar = function(_Control) {
        _inheritsLoose(Toolbar, _Control);

        function Toolbar() {
            return _Control.apply(this, arguments) || this;
        }

        var _proto = Toolbar.prototype;

        _proto.buildOn = function buildOn(map) {
            this._map = map;
            var dom = createEl('div');
            var ul = createEl('ul', 'maptalks-toolbar-hx');
            dom.appendChild(ul);

            if (this.options['vertical']) {
                addClass(dom, 'maptalks-toolbar-vertical');
            } else {
                addClass(dom, 'maptalks-toolbar-horizonal');
            }

            var me = this;

            function onButtonClick(fn, index, childIndex, targetDom) {
                var item = me._getItems()[index];

                return function(e) {
                    stopPropagation(e);
                    return fn({
                        'target': item,
                        'index': index,
                        'childIndex': childIndex,
                        'dom': targetDom
                    });
                };
            }

            var items = this.options['items'];

            if (isArrayHasData(items)) {
                for (var i = 0, len = items.length; i < len; i++) {
                    var item = items[i];
                    var li = createEl('li');

                    if (this.options['height'] !== 28) {
                        li.style.lineHeight = this.options['height'] + 'px';
                    }

                    li.style.height = this.options['height'] + 'px';
                    li.style.cursor = 'pointer';

                    if (isHTML(item['item'])) {
                        li.style.textAlign = 'center';
                        var itemSize = measureDom('div', item['item']);
                        li.innerHTML = '<div style="margin-top:' + (this.options['height'] - itemSize['height']) / 2 + 'px;">' + item['item'] + '</div>';
                    } else {
                        li.innerHTML = item['item'];
                    }

                    if (item['click']) {
                        on(li, 'click', onButtonClick(item['click'], i, null, li));
                    }

                    if (isArrayHasData(item['children'])) {
                        var dropMenu = this._createDropMenu(i);

                        li.appendChild(dropMenu);
                        li._menu = dropMenu;
                        on(li, 'mouseover', function() {
                            this._menu.style.display = '';
                        });
                        on(li, 'mouseout', function() {
                            this._menu.style.display = 'none';
                        });
                    }

                    ul.appendChild(li);
                }
            }

            return dom;
        };

        _proto._createDropMenu = function _createDropMenu(index) {
            var me = this;

            function onButtonClick(fn, index, childIndex) {
                var item = me._getItems()[index]['children'][childIndex];

                return function(e) {
                    stopPropagation(e);
                    return fn({
                        'target': item,
                        'index': index,
                        'childIndex': childIndex
                    });
                };
            }

            var menuDom = createEl('div', 'maptalks-dropMenu'),
                items = this._getItems(),
                len = items.length,
                menuUL = createEl('ul'),
                children = items[index]['children'];

            if (index === len - 1 && children) {
                menuDom.style.cssText = 'right: 0px;';
                menuUL.style.cssText = 'right: 0px;position: absolute;';

                if (this.options['reverseMenu']) {
                    menuUL.style.bottom = 0;
                }
            }

            menuDom.appendChild(createEl('em', 'maptalks-ico'));
            var liWidth = 0;

            for (var i = 0, l = children.length; i < l; i++) {
                var size = stringLength(children[i]['item'], '12px');

                if (size.width > liWidth) {
                    liWidth = size.width;
                }
            }

            for (var _i = 0, _l = children.length; _i < _l; _i++) {
                var child = children[_i];
                var li = createEl('li');
                li.innerHTML = '<a href="javascript:;">' + child['item'] + '</a>';
                li.style.cursor = 'pointer';
                li.style.width = liWidth + 24 + 'px';
                on(li.childNodes[0], 'click', onButtonClick(child['click'], index, _i));
                menuUL.appendChild(li);
            }

            if (this.options['vertical']) {
                var width = liWidth < 95 ? 95 : liWidth;

                if (this.options['reverseMenu']) {
                    menuDom.style.right = -(width + 10 * 2) + 'px';
                } else {
                    menuDom.style.left = -(width + 10 * 2) + 'px';
                }
            } else if (this.options['reverseMenu']) {
                menuDom.style.bottom = '28px';
            } else {
                menuDom.style.top = '28px';
            }

            menuDom.appendChild(menuUL);
            menuDom.style.display = 'none';
            return menuDom;
        };

        _proto._getItems = function _getItems() {
            return this.options['items'] || [];
        };

        return Toolbar;
    }(Control);

    Toolbar.mergeOptions(options$s);

    var options$t = {
        'position': 'top-left',
        'slider': true,
        'zoomLevel': true,
        'seamless': false
    };
    var UNIT = 10;

    var Zoom = function(_Control) {
        _inheritsLoose(Zoom, _Control);

        function Zoom() {
            return _Control.apply(this, arguments) || this;
        }

        var _proto = Zoom.prototype;

        _proto.buildOn = function buildOn(map) {
            var options = this.options;
            var dom = createEl('div', 'maptalks-zoom');

            if (options['zoomLevel']) {
                var levelDOM = createEl('span', 'maptalks-zoom-zoomlevel');
                dom.appendChild(levelDOM);
                this._levelDOM = levelDOM;
            }

            var zoomDOM = createEl('div', 'maptalks-zoom-slider');
            var zoomInButton = createEl('a', 'maptalks-zoom-zoomin');
            zoomInButton.href = 'javascript:;';
            zoomInButton.innerHTML = '+';
            zoomDOM.appendChild(zoomInButton);
            this._zoomInButton = zoomInButton;

            if (options['slider']) {
                var box = createEl('div', 'maptalks-zoom-slider-box');
                var ruler = createEl('div', 'maptalks-zoom-slider-ruler');
                var reading = createEl('span', 'maptalks-zoom-slider-reading');
                var dot = createEl('span', 'maptalks-zoom-slider-dot');
                ruler.appendChild(reading);
                box.appendChild(ruler);
                box.appendChild(dot);
                zoomDOM.appendChild(box);
                this._sliderBox = box;
                this._sliderRuler = ruler;
                this._sliderReading = reading;
                this._sliderDot = dot;
            }

            var zoomOutButton = createEl('a', 'maptalks-zoom-zoomout');
            zoomOutButton.href = 'javascript:;';
            zoomOutButton.innerHTML = '-';
            zoomDOM.appendChild(zoomOutButton);
            this._zoomOutButton = zoomOutButton;
            dom.appendChild(zoomDOM);
            map.on('_zoomend _zooming _zoomstart _spatialreferencechange', this._update, this);

            this._update();

            this._registerDomEvents();

            return dom;
        };

        _proto.onRemove = function onRemove() {
            this.getMap().off('_zoomend _zooming _zoomstart _spatialreferencechange', this._update, this);

            if (this._zoomInButton) {
                off(this._zoomInButton, 'click', this._onZoomInClick, this);
            }

            if (this._zoomOutButton) {
                off(this._zoomOutButton, 'click', this._onZoomOutClick, this);
            }

            if (this._sliderRuler) {
                off(this._sliderRuler, 'click', this._onClickRuler, this);
                this.dotDragger.disable();
                delete this.dotDragger;
            }
        };

        _proto._update = function _update() {
            var map = this.getMap();

            if (this._sliderBox) {
                var totalRange = (map.getMaxZoom() - map.getMinZoom()) * UNIT;
                this._sliderBox.style.height = totalRange + 16 + 'px';
                this._sliderRuler.style.height = totalRange + 8 + 'px';
                this._sliderRuler.style.cursor = 'pointer';
                var zoomRange = (map.getMaxZoom() - map.getZoom()) * UNIT;
                this._sliderReading.style.height = (map.getZoom() - map.getMinZoom() + 1) * UNIT + 'px';
                this._sliderDot.style.top = zoomRange + 'px';
            }

            this._updateText();
        };

        _proto._updateText = function _updateText() {
            if (this._levelDOM) {
                var map = this.getMap();
                var zoom = map.getZoom();

                if (!isInteger(zoom)) {
                    zoom = Math.floor(zoom * 10) / 10;
                }

                this._levelDOM.innerHTML = zoom;
            }
        };

        _proto._registerDomEvents = function _registerDomEvents() {
            if (this._zoomInButton) {
                on(this._zoomInButton, 'click', this._onZoomInClick, this);
            }

            if (this._zoomOutButton) {
                on(this._zoomOutButton, 'click', this._onZoomOutClick, this);
            }

            if (this._sliderRuler) {
                on(this._sliderRuler, 'click', this._onClickRuler, this);
                this.dotDragger = new DragHandler(this._sliderDot, {
                    'ignoreMouseleave': true
                });
                this.dotDragger.on('dragstart', this._onDotDragstart, this).on('dragging dragend', this._onDotDrag, this).enable();
            }
        };

        _proto._onZoomInClick = function _onZoomInClick(e) {
            preventDefault(e);
            this.getMap().zoomIn();
        };

        _proto._onZoomOutClick = function _onZoomOutClick(e) {
            preventDefault(e);
            this.getMap().zoomOut();
        };

        _proto._onClickRuler = function _onClickRuler(e) {
            preventDefault(e);
            var map = this.getMap(),
                point = getEventContainerPoint(e, this._sliderRuler),
                h = point.y;
            var maxZoom = map.getMaxZoom(),
                zoom = Math.floor(maxZoom - h / UNIT);
            map.setZoom(zoom);
        };

        _proto._onDotDragstart = function _onDotDragstart(e) {
            preventDefault(e.domEvent);

            var map = this.getMap(),
                origin = map.getSize().toPoint()._multi(1 / 2);

            map.onZoomStart(map.getZoom(), origin);
        };

        _proto._onDotDrag = function _onDotDrag(e) {
            preventDefault(e.domEvent);

            var map = this.getMap(),
                origin = map.getSize().toPoint()._multi(1 / 2),
                point = getEventContainerPoint(e.domEvent, this._sliderRuler),
                maxZoom = map.getMaxZoom(),
                minZoom = map.getMinZoom();

            var top = point.y,
                z = maxZoom - top / UNIT;

            if (maxZoom < z) {
                z = maxZoom;
                top = 0;
            } else if (minZoom > z) {
                z = minZoom;
                top = (maxZoom - minZoom) * UNIT;
            }

            if (e.type === 'dragging') {
                map.onZooming(z, origin, 1);
            } else if (e.type === 'dragend') {
                if (this.options['seamless']) {
                    map.onZoomEnd(z, origin);
                } else {
                    map.onZoomEnd(Math.round(z), origin);
                }
            }

            this._sliderDot.style.top = top + 'px';
            this._sliderReading.style.height = (map.getZoom() - minZoom + 1) * UNIT + 'px';

            this._updateText();
        };

        return Zoom;
    }(Control);

    Zoom.mergeOptions(options$t);
    Map$1.mergeOptions({
        'zoomControl': false
    });
    Map$1.addOnLoadHook(function() {
        if (this.options['zoomControl']) {
            this.zoomControl = new Zoom(this.options['zoomControl']);
            this.addControl(this.zoomControl);
        }
    });



    var index$5 = /*#__PURE__*/ Object.freeze({
        Control: Control,
        Attribution: Attribution,
        LayerSwitcher: LayerSwitcher,
        Overview: Overview,
        Panel: Panel,
        Scale: Scale,
        Toolbar: Toolbar,
        Zoom: Zoom
    });

    var TileSystem = function() {
        function TileSystem(sx, sy, ox, oy) {
            if (Array.isArray(sx)) {
                this.scale = {
                    x: sx[0],
                    y: sx[1]
                };
                this.origin = {
                    x: sx[2],
                    y: sx[3]
                };
            } else {
                this.scale = {
                    x: sx,
                    y: sy
                };
                this.origin = {
                    x: ox,
                    y: oy
                };
            }
        }

        TileSystem.getDefault = function getDefault(projection) {
            if (projection['code'].toLowerCase() === 'baidu') {
                return 'baidu';
            } else if (projection['code'].toLowerCase() === 'EPSG:4326'.toLowerCase()) {
                return 'tms-global-geodetic';
            } else if (projection['code'].toLowerCase() === 'identity') {
                return [1, -1, 0, 0];
            } else {
                return 'web-mercator';
            }
        };

        return TileSystem;
    }();

    var semiCircum = 6378137 * Math.PI;
    extend(TileSystem, {
        'web-mercator': new TileSystem([1, -1, -semiCircum, semiCircum]),
        'tms-global-mercator': new TileSystem([1, 1, -semiCircum, -semiCircum]),
        'tms-global-geodetic': new TileSystem([1, 1, -180, -90]),
        'baidu': new TileSystem([1, 1, 0, 0])
    });

    var TileConfig = function() {
        function TileConfig(map, tileSystem, fullExtent, tileSize) {
            this.map = map;
            this.tileSize = tileSize;
            this.fullExtent = fullExtent;
            this.prepareTileInfo(tileSystem, fullExtent);
            this._xScale = fullExtent['right'] >= fullExtent['left'] ? 1 : -1;
            this._yScale = fullExtent['top'] >= fullExtent['bottom'] ? 1 : -1;
            this._pointOrigin = map._prjToPoint(new Point(this.tileSystem['origin']), map.getGLZoom());
            this._glRes = map.getResolution(map.getGLZoom());
        }

        var _proto = TileConfig.prototype;

        _proto.prepareTileInfo = function prepareTileInfo(tileSystem, fullExtent) {
            if (isString(tileSystem)) {
                tileSystem = TileSystem[tileSystem.toLowerCase()];
            } else if (Array.isArray(tileSystem)) {
                tileSystem = new TileSystem(tileSystem);
            }

            if (!tileSystem) {
                throw new Error('Invalid TileSystem');
            }

            this.tileSystem = tileSystem;
            var a = fullExtent['right'] > fullExtent['left'] ? 1 : -1,
                b = fullExtent['top'] > fullExtent['bottom'] ? -1 : 1,
                c = tileSystem['origin']['x'],
                d = tileSystem['origin']['y'];
            this.transformation = new Transformation([a, b, c, d]);
        };

        _proto._getTileNum = function _getTileNum(point, res) {
            var tileSystem = this.tileSystem,
                tileSize = this['tileSize'],
                delta = 1E-7;
            var tileX = Math.floor(delta * tileSystem['scale']['x'] + point.x / (tileSize['width'] * res));
            var tileY = Math.ceil(delta * tileSystem['scale']['y'] + point.y / (tileSize['height'] * res));
            return {
                'x': tileSystem['scale']['x'] * tileX,
                'y': tileSystem['scale']['y'] * tileY
            };
        };

        _proto.getTileIndex = function getTileIndex(pCoord, res, repeatWorld) {
            var tileSystem = this.tileSystem;
            var point = this.transformation.transform(pCoord, 1);

            var tileIndex = this._getTileNum(point, res);

            if (tileSystem['scale']['x'] < 0) {
                tileIndex['x'] -= 1;
            }

            if (tileSystem['scale']['y'] > 0) {
                tileIndex['y'] -= 1;
            }

            return this.getNeighorTileIndex(tileIndex['x'], tileIndex['y'], 0, 0, res, repeatWorld);
        };

        _proto.getNeighorTileIndex = function getNeighorTileIndex(tileX, tileY, offsetX, offsetY, res, repeatWorld) {
            var tileSystem = this.tileSystem;
            var x = tileX + tileSystem['scale']['x'] * offsetX;
            var y = tileY - tileSystem['scale']['y'] * offsetY;
            var out = false;
            var idx = x;
            var idy = y;

            var ext = this._getTileFullIndex(res);

            if (repeatWorld) {
                if (repeatWorld === true || repeatWorld === 'x') {
                    if (ext['xmax'] === ext['xmin']) {
                        x = ext['xmin'];
                    } else if (x < ext['xmin']) {
                        x = ext['xmax'] - (ext['xmin'] - x) % (ext['xmax'] - ext['xmin']);

                        if (x === ext['xmax']) {
                            x = ext['xmin'];
                        }
                    } else if (x >= ext['xmax']) {
                        x = ext['xmin'] + (x - ext['xmin']) % (ext['xmax'] - ext['xmin']);
                    }
                }

                if (repeatWorld === true || repeatWorld === 'y') {
                    if (ext['ymax'] === ext['ymin']) {
                        y = ext['ymin'];
                    } else if (y >= ext['ymax']) {
                        y = ext['ymin'] + (y - ext['ymin']) % (ext['ymax'] - ext['ymin']);
                    } else if (y < ext['ymin']) {
                        y = ext['ymax'] - (ext['ymin'] - y) % (ext['ymax'] - ext['ymin']);

                        if (y === ext['ymax']) {
                            y = ext['ymin'];
                        }
                    }
                }
            }

            if (x < ext['xmin'] || x > ext['xmax'] || y > ext['ymax'] || y < ext['ymin']) {
                out = true;
            }

            return {
                'x': x,
                'y': y,
                'idx': idx,
                'idy': idy,
                out: out
            };
        };

        _proto._getTileFullIndex = function _getTileFullIndex(res) {
            if (!this._tileFullIndex) {
                this._tileFullIndex = {};
            }

            if (this._tileFullIndex[res]) {
                return this._tileFullIndex[res];
            }

            var ext = this.fullExtent;
            var transformation = this.transformation;

            var nwIndex = this._getTileNum(transformation.transform(new Coordinate(ext['left'], ext['top']), 1), res);

            var seIndex = this._getTileNum(transformation.transform(new Coordinate(ext['right'], ext['bottom']), 1), res);

            var tileSystem = this.tileSystem;

            if (tileSystem['scale']['x'] < 0) {
                nwIndex.x -= 1;
                seIndex.x -= 1;
            }

            if (tileSystem['scale']['y'] > 0) {
                nwIndex.y -= 1;
                seIndex.y -= 1;
            }

            this._tileFullIndex[res] = new Extent(nwIndex, seIndex);
            return this._tileFullIndex[res];
        };

        _proto.getTilePrjNW = function getTilePrjNW(tileX, tileY, res) {
            var tileSystem = this.tileSystem;
            var tileSize = this['tileSize'];
            var y = tileSystem['origin']['y'] + this._yScale * tileSystem['scale']['y'] * (tileY + (tileSystem['scale']['y'] === 1 ? 1 : 0)) * res * tileSize['height'];
            var x = tileSystem['origin']['x'] + this._xScale * tileSystem['scale']['x'] * (tileX + (tileSystem['scale']['x'] === 1 ? 0 : 1)) * res * tileSize['width'];
            return new Coordinate(x, y);
        };

        _proto.getTilePointNW = function getTilePointNW(tileX, tileY, res) {
            var scale = this._glRes / res;
            var tileSystem = this.tileSystem;
            var tileSize = this['tileSize'];
            var y = this._pointOrigin.y * scale + this._yScale * tileSystem['scale']['y'] * (tileY + (tileSystem['scale']['y'] === 1 ? 1 : 0)) * tileSize['height'];
            var x = this._pointOrigin.x * scale + this._xScale * tileSystem['scale']['x'] * (tileX + (tileSystem['scale']['x'] === 1 ? 0 : 1)) * tileSize['width'];
            return new Point(x, y);
        };

        _proto.getTilePrjSE = function getTilePrjSE(tileX, tileY, res) {
            var tileSystem = this.tileSystem;
            var tileSize = this['tileSize'];
            var y = tileSystem['origin']['y'] + this._yScale * tileSystem['scale']['y'] * (tileY + (tileSystem['scale']['y'] === 1 ? 0 : 1)) * res * tileSize['height'];
            var x = tileSystem['origin']['x'] + this._xScale * tileSystem['scale']['x'] * (tileX + (tileSystem['scale']['x'] === 1 ? 1 : 0)) * res * tileSize['width'];
            return new Coordinate(x, y);
        };

        _proto.getTilePointSE = function getTilePointSE(tileX, tileY, res) {
            var scale = this._glRes / res;
            var tileSystem = this.tileSystem;
            var tileSize = this['tileSize'];
            var y = this._pointOrigin.y * scale + this._yScale * tileSystem['scale']['y'] * (tileY + (tileSystem['scale']['y'] === 1 ? 0 : 1)) * tileSize['height'];
            var x = this._pointOrigin.x * scale + this._xScale * tileSystem['scale']['x'] * (tileX + (tileSystem['scale']['x'] === 1 ? 1 : 0)) * tileSize['width'];
            return new Point(x, y);
        };

        _proto.getTilePrjExtent = function getTilePrjExtent(tileX, tileY, res) {
            var nw = this.getTilePrjNW(tileX, tileY, res),
                se = this.getTilePrjSE(tileX, tileY, res);
            return new Extent(nw, se);
        };

        return TileConfig;
    }();

    var planes = [];

    for (var i = 0; i < 6; i++) {
        planes[i] = [];
    }
    var p = [];

    function intersectsBox(matrix, box, mask) {
        setPlanes(matrix);

        for (var i = 0; i < 6; i++) {
            if (mask && mask.charAt(i) === '0') {
                continue;
            }

            var plane = planes[i];
            p[0] = plane[0] > 0 ? box[1][0] : box[0][0];
            p[1] = plane[1] > 0 ? box[1][1] : box[0][1];
            p[2] = plane[2] > 0 ? box[1][2] : box[0][2];

            if (distanceToPoint(plane, p) < 0) {
                return false;
            }
        }

        return true;
    }

    function setPlanes(m) {
        var me = m;
        var me0 = me[0],
            me1 = me[1],
            me2 = me[2],
            me3 = me[3];
        var me4 = me[4],
            me5 = me[5],
            me6 = me[6],
            me7 = me[7];
        var me8 = me[8],
            me9 = me[9],
            me10 = me[10],
            me11 = me[11];
        var me12 = me[12],
            me13 = me[13],
            me14 = me[14],
            me15 = me[15];
        setComponents(planes[0], me3 - me0, me7 - me4, me11 - me8, me15 - me12);
        setComponents(planes[1], me3 + me0, me7 + me4, me11 + me8, me15 + me12);
        setComponents(planes[2], me3 + me1, me7 + me5, me11 + me9, me15 + me13);
        setComponents(planes[3], me3 - me1, me7 - me5, me11 - me9, me15 - me13);
        setComponents(planes[4], me3 - me2, me7 - me6, me11 - me10, me15 - me14);
        setComponents(planes[5], me3 + me2, me7 + me6, me11 + me10, me15 + me14);
    }

    var normalLength = 1.0 / 6;

    function setComponents(out, x, y, z, w) {
        out[0] = x * normalLength;
        out[1] = y * normalLength;
        out[2] = z * normalLength;
        out[3] = w * normalLength;
        return out;
    }

    function distanceToPoint(plane, p) {
        return plane[0] * p[0] + plane[1] * p[1] + plane[2] * p[2] + plane[3];
    }

    var isSetAvailable = typeof Set !== 'undefined';

    var TileHashset = function() {
        function TileHashset() {
            this._table = isSetAvailable ? new Set() : {};
        }

        var _proto = TileHashset.prototype;

        _proto.add = function add$$1(key) {
            if (isSetAvailable) {
                this._table.add(key);
            } else {
                this._table[key] = true;
            }
        };

        _proto.has = function has(key) {
            if (isSetAvailable) {
                return this._table.has(key);
            } else {
                return this._table[key];
            }
        };

        _proto.reset = function reset() {
            if (isSetAvailable) {
                this._table.clear();
            } else {
                this._table = {};
            }
        };

        return TileHashset;
    }();

    var options$u = {
        'urlTemplate': null,
        'subdomains': null,
        'errorUrl': null,
        'repeatWorld': true,
        'background': true,
        'backgroundZoomDiff': 6,
        'loadingLimitOnInteracting': 3,
        'tileRetryCount': 0,
        'placeholder': false,
        'crossOrigin': null,
        'tileSize': [256, 256],
        'offset': [0, 0],
        'tileSystem': null,
        'fadeAnimation': !IS_NODE,
        'debug': false,
        'spatialReference': null,
        'maxCacheSize': 256,
        'renderer': function() {
            return Browser$1.webgl ? 'gl' : 'canvas';
        }(),
        'clipByPitch': true,
        'maxAvailableZoom': null,
        'cascadeTiles': true,
        'zoomOffset': 0
    };
    var URL_PATTERN$1 = /\{ *([\w_]+) *\}/g;
    var TEMP_POINT = new Point(0, 0);
    var TEMP_POINT0$3 = new Point(0, 0);
    var TEMP_POINT1$1 = new Point(0, 0);
    var TEMP_POINT2 = new Point(0, 0);
    var TEMP_POINT3 = new Point(0, 0);
    var TEMP_POINT4 = new Point(0, 0);
    var TEMP_POINT6 = new Point(0, 0);
    var TILE_BOX = [
        [0, 0, 0],
        [0, 0, 0]
    ];
    var ARR3 = [];

    var TileLayer = function(_Layer) {
        _inheritsLoose(TileLayer, _Layer);

        function TileLayer() {
            return _Layer.apply(this, arguments) || this;
        }

        TileLayer.fromJSON = function fromJSON(layerJSON) {
            if (!layerJSON || layerJSON['type'] !== 'TileLayer') {
                return null;
            }

            return new TileLayer(layerJSON['id'], layerJSON['options']);
        };

        var _proto2 = TileLayer.prototype;

        _proto2.getTileSize = function getTileSize() {
            if (this._tileSize) {
                return this._tileSize;
            }

            var size = this.options['tileSize'];

            if (isNumber(size)) {
                size = [size, size];
            }

            this._tileSize = new Size(size);
            return this._tileSize;
        };

        _proto2.getTiles = function getTiles(z, parentLayer) {
            var map = this.getMap();
            var pitch = map.getPitch();
            var parentRenderer = parentLayer && parentLayer.getRenderer();
            var mapExtent = map.getContainerExtent();
            var tileGrids = [];
            var count = 0;
            var minZoom = this.getMinZoom();
            var cascadePitch0 = map.options['cascadePitches'][0];
            var cascadePitch1 = map.options['cascadePitches'][1];
            var visualHeight1 = Math.floor(map._getVisualHeight(cascadePitch1));
            var tileZoom = isNil(z) ? this._getTileZoom(map.getZoom()) : z;
            this._visitedTiles = new TileHashset();
            this._coordCache = {};

            if (!isNil(z) || !this.options['cascadeTiles'] || pitch <= cascadePitch0 || !isNil(minZoom) && tileZoom <= minZoom) {
                var containerExtent = pitch <= cascadePitch1 ? mapExtent : new PointExtent(0, map.height - visualHeight1, map.width, map.height);

                var _currentTiles = this._getTiles(tileZoom, containerExtent, 2, parentRenderer);

                if (_currentTiles) {
                    count += _currentTiles.tiles.length;
                    tileGrids.push(_currentTiles);
                }

                return {
                    tileGrids: tileGrids,
                    count: count
                };
            }

            var visualHeight0 = Math.floor(map._getVisualHeight(cascadePitch0));
            var extent0 = new PointExtent(0, map.height - visualHeight0, map.width, map.height);

            var currentTiles = this._getTiles(tileZoom, extent0, 0, parentRenderer);

            count += currentTiles ? currentTiles.tiles.length : 0;
            tileGrids.push(currentTiles);
            var cascadeHeight = extent0.ymin;
            var d = map.getSpatialReference().getZoomDirection();
            var cascadeLevels = d;
            var cascadeTiles1;

            if (pitch > cascadePitch1) {
                if (tileZoom - cascadeLevels <= minZoom) {
                    cascadeLevels = 0;
                }

                var extent1 = new PointExtent(0, map.height - visualHeight1, map.width, cascadeHeight);
                cascadeTiles1 = this._getTiles(tileZoom - cascadeLevels, extent1, 1, parentRenderer);
                count += cascadeTiles1 ? cascadeTiles1.tiles.length : 0;
                cascadeHeight = extent1.ymin;
                cascadeLevels += 4 * d;
            }

            var cascadeTiles2;

            if (tileZoom - cascadeLevels >= minZoom) {
                var extent2 = new PointExtent(0, mapExtent.ymin, map.width, cascadeHeight);
                cascadeTiles2 = this._getTiles(tileZoom - cascadeLevels, extent2, 2, parentRenderer);
                count += cascadeTiles2 ? cascadeTiles2.tiles.length : 0;
                tileGrids.push(cascadeTiles2);
            }

            if (cascadeTiles1 && cascadeTiles2) {
                tileGrids[1] = cascadeTiles2;
                tileGrids[2] = cascadeTiles1;
            }

            return {
                tileGrids: tileGrids,
                count: count
            };
        };

        _proto2.getTileUrl = function getTileUrl(x, y, z) {
            var urlTemplate = this.options['urlTemplate'];
            var domain = '';

            if (this.options['subdomains']) {
                var subdomains = this.options['subdomains'];

                if (isArrayHasData(subdomains)) {
                    var length$$1 = subdomains.length;
                    var s = (x + y) % length$$1;

                    if (s < 0) {
                        s = 0;
                    }

                    domain = subdomains[s];
                }
            }

            if (isFunction(urlTemplate)) {
                return urlTemplate(x, y, z, domain);
            }

            var data = {
                'x': x,
                'y': y,
                'z': z,
                's': domain
            };
            return urlTemplate.replace(URL_PATTERN$1, function(str, key) {
                var value = data[key];

                if (value === undefined) {
                    throw new Error('No value provided for variable ' + str);
                } else if (typeof value === 'function') {
                    value = value(data);
                }

                return value;
            });
        };

        _proto2.clear = function clear() {
            if (this._renderer) {
                this._renderer.clear();
            }

            this.fire('clear');
            return this;
        };

        _proto2.toJSON = function toJSON() {
            var profile = {
                'type': this.getJSONType(),
                'id': this.getId(),
                'options': this.config()
            };
            return profile;
        };

        _proto2.getSpatialReference = function getSpatialReference() {
            var map = this.getMap();

            if (map && (!this.options['spatialReference'] || SpatialReference.equals(this.options['spatialReference'], map.options['spatialReference']))) {
                return map.getSpatialReference();
            }

            this._sr = this._sr || new SpatialReference(this.options['spatialReference']);

            if (this._srMinZoom === undefined) {
                this._srMinZoom = this._sr.getMinZoom();
                this._srMaxZoom = this._sr.getMaxZoom();
            }

            return this._sr;
        };

        _proto2.getMinZoom = function getMinZoom() {
            var sr = this.getSpatialReference();

            if (sr !== this.getMap().getSpatialReference()) {
                return Math.max(_Layer.prototype.getMinZoom.call(this), this._srMinZoom);
            }

            return _Layer.prototype.getMinZoom.call(this);
        };

        _proto2.getMaxZoom = function getMaxZoom() {
            var sr = this.getSpatialReference();

            if (sr !== this.getMap().getSpatialReference()) {
                return Math.min(_Layer.prototype.getMaxZoom.call(this), this._srMaxZoom);
            }

            return _Layer.prototype.getMaxZoom.call(this);
        };

        _proto2._getTileZoom = function _getTileZoom(zoom) {
            if (!isInteger(zoom)) {
                zoom = Math.round(zoom);
            }

            var maxZoom = this.options['maxAvailableZoom'];

            if (!isNil(maxZoom) && zoom > maxZoom) {
                zoom = maxZoom;
            }

            return zoom;
        };

        _proto2._getTiles = function _getTiles(tileZoom, containerExtent, cascadeLevel, parentRenderer) {
            var _this = this;

            var map = this.getMap();
            var z = tileZoom;
            var frustumMatrix = map.projViewMatrix;

            if (cascadeLevel < 2) {
                if (cascadeLevel === 0) {
                    z -= 1;
                }

                frustumMatrix = cascadeLevel === 0 ? map.cascadeFrustumMatrix0 : cascadeLevel === 1 ? map.cascadeFrustumMatrix1 : map.projViewMatrix;
            }

            var zoom = z + this.options['zoomOffset'];

            var offset = this._getTileOffset(zoom),
                hasOffset = offset[0] || offset[1];

            var emptyGrid = {
                'zoom': z,
                'extent': null,
                'offset': offset,
                'tiles': []
            };

            if (zoom < 0) {
                return emptyGrid;
            }

            var minZoom = this.getMinZoom(),
                maxZoom = this.getMaxZoom();

            if (!map || !this.isVisible() || !map.width || !map.height) {
                return emptyGrid;
            }

            if (!isNil(minZoom) && z < minZoom || !isNil(maxZoom) && z > maxZoom) {
                return emptyGrid;
            }

            var tileConfig = this._getTileConfig();

            if (!tileConfig) {
                return emptyGrid;
            }

            var tileOffsets = {
                zoom: offset
            };
            var sr = this.getSpatialReference();
            var mapSR = map.getSpatialReference();
            var res = sr.getResolution(zoom);
            var glScale = map.getGLScale(z);
            var repeatWorld = sr === mapSR && this.options['repeatWorld'];
            var extent2d = containerExtent.convertTo(function(c) {
                var result;

                if (c.y > 0 && c.y < map.height) {
                    var key = (c.x === 0 ? 0 : 1) + c.y;

                    if (!_this._coordCache[key]) {
                        _this._coordCache[key] = map._containerPointToPoint(c);
                    }

                    result = _this._coordCache[key];
                }

                result = map._containerPointToPoint(c, undefined, TEMP_POINT);
                return result;
            });

            var maskExtent = this._getMask2DExtent();

            if (maskExtent) {
                var intersection = maskExtent.intersection(extent2d);

                if (!intersection) {
                    return emptyGrid;
                }

                containerExtent = intersection.convertTo(function(c) {
                    return map._pointToContainerPoint(c, undefined, 0, TEMP_POINT);
                });
            }

            var prjCenter = map._containerPointToPrj(containerExtent.getCenter(), TEMP_POINT0$3);

            var centerPoint = map._prjToPoint(prjCenter, zoom, TEMP_POINT1$1);

            var c;

            if (hasOffset) {
                c = this._project(map._pointToPrj(centerPoint._add(offset), zoom, TEMP_POINT1$1), TEMP_POINT1$1);
            } else {
                c = this._project(prjCenter, TEMP_POINT1$1);
            }

            var extentScale = map.getGLScale() / map.getGLScale(zoom);
            TEMP_POINT2.x = extent2d.xmin * extentScale;
            TEMP_POINT2.y = extent2d.ymax * extentScale;
            TEMP_POINT3.x = extent2d.xmax * extentScale;
            TEMP_POINT3.y = extent2d.ymin * extentScale;

            var pmin = this._project(map._pointToPrj(TEMP_POINT2._add(offset), zoom, TEMP_POINT2), TEMP_POINT2);

            var pmax = this._project(map._pointToPrj(TEMP_POINT3._add(offset), zoom, TEMP_POINT3), TEMP_POINT3);

            var centerTile = tileConfig.getTileIndex(c, res, repeatWorld);
            var ltTile = tileConfig.getTileIndex(pmin, res, repeatWorld);
            var rbTile = tileConfig.getTileIndex(pmax, res, repeatWorld);
            var top = Math.ceil(Math.abs(centerTile.idy - ltTile.idy)),
                left = Math.ceil(Math.abs(centerTile.idx - ltTile.idx)),
                bottom = Math.ceil(Math.abs(centerTile.idy - rbTile.idy)),
                right = Math.ceil(Math.abs(centerTile.idx - rbTile.idx));
            var allCount = (top + bottom + 1) * (left + right + 1);
            var tileSize = this.getTileSize();

            var renderer = this.getRenderer() || parentRenderer,
                scale = this._getTileConfig().tileSystem.scale;

            var tiles = [],
                extent = new PointExtent();
            var tilePoint = new Point(0, 0);

            for (var i = -top; i <= bottom; i++) {
                var j = -left;
                var leftVisitEnd = -Infinity;
                var rightVisitEnd = false;

                while (j >= leftVisitEnd && j <= right) {
                    var idx = tileConfig.getNeighorTileIndex(centerTile.idx, centerTile.idy, j, i, res, repeatWorld);

                    if (leftVisitEnd === -Infinity) {
                        j++;
                    } else {
                        j--;
                    }

                    var tileId = this._getTileId(idx.idx, idx.idy, z);

                    if (idx.out || this._visitedTiles && this._visitedTiles.has(tileId)) {
                        continue;
                    }

                    var tileInfo = renderer && renderer.isTileCachedOrLoading(tileId);

                    if (tileInfo) {
                        tileInfo = tileInfo.info;
                    }

                    var p = void 0;

                    if (tileInfo) {
                        var _tileInfo = tileInfo,
                            _extent2d = _tileInfo.extent2d;
                        tilePoint.set(_extent2d.xmin, _extent2d.ymax);
                        p = tilePoint;
                    } else if (!this._hasOwnSR) {
                        p = tileConfig.getTilePointNW(idx.x, idx.y, res);
                    } else {
                        var pnw = tileConfig.getTilePrjNW(idx.x, idx.y, res);
                        p = map._prjToPoint(this._unproject(pnw, TEMP_POINT3), z);
                    }

                    var width = void 0,
                        height = void 0;

                    if (sr === mapSR) {
                        width = tileSize.width;
                        height = tileSize.height;
                    } else {
                        var pp = void 0;

                        if (!this._hasOwnSR) {
                            pp = tileConfig.getTilePointSE(idx.x, idx.y, res);
                        } else {
                            var pse = tileConfig.getTilePrjSE(idx.x, idx.y, res);
                            pp = map._prjToPoint(this._unproject(pse, TEMP_POINT3), z, TEMP_POINT3);
                        }

                        width = Math.ceil(Math.abs(pp.x - p.x));
                        height = Math.ceil(Math.abs(pp.y - p.y));
                    }

                    var dx = scale.x * (idx.idx - idx.x) * width,
                        dy = scale.y * (idx.idy - idx.y) * height;

                    if (!tileInfo && (dx || dy)) {
                        p._add(dx, dy);
                    }

                    var tileExtent = tileInfo && tileInfo.extent2d || new PointExtent(p.x, p.y - height, p.x + width, p.y);

                    if (allCount <= 4 || rightVisitEnd || this._isTileInExtent(frustumMatrix, tileExtent, offset, glScale)) {
                        if (this._visitedTiles && cascadeLevel === 0) {
                            this._visitedTiles.add(tileId);
                        }

                        if (cascadeLevel === 0) {
                            this._splitTiles(frustumMatrix, tiles, renderer, idx, z + 1, tileExtent, dx, dy, tileOffsets, parentRenderer);

                            extent._combine(tileExtent);
                        } else {
                            if (!tileInfo) {
                                tileInfo = {
                                    'z': z,
                                    'x': idx.x,
                                    'y': idx.y,
                                    'extent2d': tileExtent,
                                    'offset': offset,
                                    'id': tileId,
                                    'url': this.getTileUrl(idx.x, idx.y, z)
                                };

                                if (parentRenderer) {
                                    tileInfo['layer'] = this.getId();
                                }
                            } else {
                                tileInfo.offset[0] = offset[0];
                                tileInfo.offset[1] = offset[1];
                            }

                            tiles.push(tileInfo);

                            extent._combine(tileExtent);
                        }

                        if (leftVisitEnd === -Infinity) {
                            leftVisitEnd = j;
                            j = right;
                        } else if (!rightVisitEnd) {
                            rightVisitEnd = true;
                        }
                    }
                }
            }

            if (tiles.length) {
                var center = map._containerPointToPoint(containerExtent.getCenter(), z, TEMP_POINT)._add(offset);

                var point0 = new Point(0, 0);
                var point1 = new Point(0, 0);
                tiles.sort(function(a, b) {
                    point0.set((a.extent2d.xmin + a.extent2d.xmax) / 2, (a.extent2d.ymin + a.extent2d.ymax) / 2);
                    point1.set((b.extent2d.xmin + b.extent2d.xmax) / 2, (b.extent2d.ymin + b.extent2d.ymax) / 2);
                    return point0.distanceTo(center) - point1.distanceTo(center);
                });
            }

            return {
                'offset': offset,
                'zoom': tileZoom,
                'extent': extent,
                'tiles': tiles
            };
        };

        _proto2._splitTiles = function _splitTiles(frustumMatrix, tiles, renderer, tileIdx, z, tileExtent, dx, dy, tileOffsets, parentRenderer) {
            var yOrder = this._getTileConfig().tileSystem.scale.y;

            var glScale = this.getMap().getGLScale(z);
            var corner = TEMP_POINT4.set(tileExtent.xmin * 2, yOrder < 0 ? tileExtent.ymax * 2 : tileExtent.ymin * 2);
            var w = tileExtent.getWidth();
            var h = tileExtent.getHeight();
            var idx = tileIdx.idx * 2;
            var idy = tileIdx.idy * 2;
            var x = tileIdx.x * 2;
            var y = tileIdx.y * 2;

            var tile = this._checkAndAddTile(frustumMatrix, renderer, idx, idy, x, y, z, 0, 0, w, h, corner, glScale, tileOffsets, parentRenderer);

            if (tile) tiles.push(tile);
            tile = this._checkAndAddTile(frustumMatrix, renderer, idx, idy, x, y, z, 0, 1, w, h, corner, glScale, tileOffsets, parentRenderer);
            if (tile) tiles.push(tile);
            tile = this._checkAndAddTile(frustumMatrix, renderer, idx, idy, x, y, z, 1, 0, w, h, corner, glScale, tileOffsets, parentRenderer);
            if (tile) tiles.push(tile);
            tile = this._checkAndAddTile(frustumMatrix, renderer, idx, idy, x, y, z, 1, 1, w, h, corner, glScale, tileOffsets, parentRenderer);
            if (tile) tiles.push(tile);
        };

        _proto2._checkAndAddTile = function _checkAndAddTile(frustumMatrix, renderer, idx, idy, x, y, z, i, j, w, h, corner, glScale, tileOffsets, parentRenderer) {
            var tileId = this._getTileId(idx + i, idy + j, z);

            if (this._visitedTiles && this._visitedTiles.has(tileId)) {
                return null;
            }

            var offset = tileOffsets[z];

            if (!offset) {
                offset = tileOffsets[z] = this._getTileOffset(z);
            }

            var yOrder = this._getTileConfig().tileSystem.scale.y;

            var childExtent = new PointExtent(corner.x + i * w, corner.y + yOrder * j * h, corner.x + (i + 1) * w, corner.y + yOrder * (j + 1) * h);

            if (!this._isSplittedTileInExtent(frustumMatrix, childExtent, offset, glScale)) {
                return null;
            }

            var tileInfo = renderer && renderer.isTileCachedOrLoading(tileId);

            if (!tileInfo) {
                tileInfo = {
                    'z': z,
                    'x': x + i,
                    'y': y + j,
                    'extent2d': childExtent,
                    'id': tileId,
                    'offset': offset,
                    'url': this.getTileUrl(x + i, y + j, z + this.options['zoomOffset'])
                };

                if (parentRenderer) {
                    tileInfo['layer'] = this.getId();
                }
            } else {
                tileInfo = tileInfo.info;
            }

            return tileInfo;
        };

        _proto2._getTileOffset = function _getTileOffset(z) {
            var offset = this.options['offset'];

            if (isFunction(offset)) {
                offset = offset(z);
            }

            return offset;
        };

        _proto2._getTileId = function _getTileId(x, y, zoom, id) {
            return (id || this.getId()) + "_" + y + "_" + x + "_" + zoom;
        };

        _proto2._project = function _project(pcoord, out) {
            if (this._hasOwnSR) {
                var map = this.getMap();
                var mapProjection = map.getProjection();
                var projection = this.getSpatialReference().getProjection();
                return projection.project(mapProjection.unproject(pcoord, out), out);
            } else {
                return pcoord;
            }
        };

        _proto2._unproject = function _unproject(pcoord, out) {
            if (this._hasOwnSR) {
                var map = this.getMap();
                var sr = this.getSpatialReference();
                var mapProjection = map.getProjection();
                var projection = sr.getProjection();
                return mapProjection.project(projection.unproject(pcoord, out), out);
            } else {
                return pcoord;
            }
        };

        _proto2._initTileConfig = function _initTileConfig() {
            var map = this.getMap(),
                tileSize = this.getTileSize();
            var sr = this.getSpatialReference();
            var projection = sr.getProjection(),
                fullExtent = sr.getFullExtent();
            this._defaultTileConfig = new TileConfig(map, TileSystem.getDefault(projection), fullExtent, tileSize);

            if (this.options['tileSystem']) {
                this._tileConfig = new TileConfig(map, this.options['tileSystem'], fullExtent, tileSize);
            }

            this._hasOwnSR = sr !== map.getSpatialReference();
        };

        _proto2._getTileConfig = function _getTileConfig() {
            if (!this._defaultTileConfig) {
                this._initTileConfig();
            }

            return this._tileConfig || this._defaultTileConfig;
        };

        _proto2._bindMap = function _bindMap(map) {
            var baseLayer = map.getBaseLayer();

            if (baseLayer === this) {
                if (!baseLayer.options.hasOwnProperty('forceRenderOnMoving')) {
                    this.config({
                        'forceRenderOnMoving': true
                    });
                }
            }

            return _Layer.prototype._bindMap.apply(this, arguments);
        };

        _proto2._isTileInExtent = function _isTileInExtent(frustumMatrix, tileExtent, offset, glScale) {
            var map = this.getMap();
            var matrix;

            if (frustumMatrix !== map.projViewMatrix) {
                var tileCenter = tileExtent.getCenter(TEMP_POINT6)._sub(offset[0], offset[1])._multi(glScale);

                set$2(ARR3, tileCenter.x, tileCenter.y, 0);
                var ndc = transformMat4(ARR3, ARR3, map.projViewMatrix);
                matrix = ndc[1] < 0 ? map.projViewMatrix : frustumMatrix;
            } else {
                matrix = map.projViewMatrix;
            }

            TILE_BOX[0][0] = (tileExtent.xmin - offset[0]) * glScale;
            TILE_BOX[0][1] = (tileExtent.ymin - offset[1]) * glScale;
            TILE_BOX[1][0] = (tileExtent.xmax - offset[0]) * glScale;
            TILE_BOX[1][1] = (tileExtent.ymax - offset[1]) * glScale;
            return intersectsBox(matrix, TILE_BOX);
        };

        _proto2._isSplittedTileInExtent = function _isSplittedTileInExtent(frustumMatrix, tileExtent, offset, glScale) {
            var map = this.getMap();
            TILE_BOX[0][0] = (tileExtent.xmin - offset[0]) * glScale;
            TILE_BOX[0][1] = (tileExtent.ymin - offset[1]) * glScale;
            TILE_BOX[1][0] = (tileExtent.xmax - offset[0]) * glScale;
            TILE_BOX[1][1] = (tileExtent.ymax - offset[1]) * glScale;
            return intersectsBox(map.projViewMatrix, TILE_BOX);
        };

        _proto2.getEvents = function getEvents() {
            return {
                'spatialreferencechange': this._onSpatialReferenceChange
            };
        };

        _proto2._onSpatialReferenceChange = function _onSpatialReferenceChange() {
            delete this._tileConfig;
            delete this._defaultTileConfig;
            delete this._sr;
            var renderer = this.getRenderer();

            if (renderer) {
                renderer.clear();
            }
        };

        return TileLayer;
    }(Layer);

    TileLayer.registerJSONType('TileLayer');
    TileLayer.mergeOptions(options$u);

    var GroupTileLayer = function(_TileLayer) {
        _inheritsLoose(GroupTileLayer, _TileLayer);

        GroupTileLayer.fromJSON = function fromJSON(layerJSON) {
            if (!layerJSON || layerJSON['type'] !== 'GroupTileLayer') {
                return null;
            }

            var layers = layerJSON['layers'].map(function(json) {
                return Layer.fromJSON(json);
            });
            return new GroupTileLayer(layerJSON['id'], layers, layerJSON['options']);
        };

        function GroupTileLayer(id, layers, options) {
            var _this;

            _this = _TileLayer.call(this, id, options) || this;
            _this.layers = layers || [];

            _this._checkChildren();

            _this.layerMap = {};
            _this._groupChildren = [];
            return _this;
        }

        var _proto = GroupTileLayer.prototype;

        _proto.getLayers = function getLayers() {
            return this.layers;
        };

        _proto.toJSON = function toJSON() {
            var profile = {
                'type': this.getJSONType(),
                'id': this.getId(),
                'layers': this.layers.map(function(layer) {
                    return layer.toJSON();
                }),
                'options': this.config()
            };
            return profile;
        };

        _proto.getTiles = function getTiles(z) {
            var layers = this.layers;
            var tiles = [];
            var count = 0;

            for (var i = 0, l = layers.length; i < l; i++) {
                var layer = layers[i];

                if (!layer.options['visible']) {
                    continue;
                }

                var childGrid = layer.getTiles(z, this);

                if (!childGrid || childGrid.count === 0) {
                    continue;
                }

                count += childGrid.count;
                pushIn(tiles, childGrid.tileGrids);
            }

            return {
                count: count,
                tileGrids: tiles
            };
        };

        _proto.onAdd = function onAdd() {
            var _this2 = this;

            var map = this.getMap();
            this.layers.forEach(function(layer) {
                _this2.layerMap[layer.getId()] = layer;

                if (layer.getChildLayer) {
                    _this2._groupChildren.push(layer);
                }

                layer._bindMap(map);

                layer.on('show hide', _this2._onLayerShowHide, _this2);
            });

            _TileLayer.prototype.onAdd.call(this);
        };

        _proto.onRemove = function onRemove() {
            var _this3 = this;

            this.layers.forEach(function(layer) {
                layer._doRemove();

                layer.off('show hide', _this3._onLayerShowHide, _this3);
            });
            this.layerMap = {};
            this._groupChildren = [];

            _TileLayer.prototype.onRemove.call(this);
        };

        _proto.getChildLayer = function getChildLayer(id) {
            var layer = this.layerMap[id];

            if (layer) {
                return layer;
            }

            for (var i = 0; i < this._groupChildren.length; i++) {
                var child = this._groupChildren[i].getChildLayer(id);

                if (child) {
                    return child;
                }
            }

            return null;
        };

        _proto._onLayerShowHide = function _onLayerShowHide() {
            var renderer = this.getRenderer();

            if (renderer) {
                renderer.setToRedraw();
            }
        };

        _proto.isVisible = function isVisible() {
            if (!_TileLayer.prototype.isVisible.call(this)) {
                return false;
            }

            var children = this.layers;

            for (var i = 0, l = children.length; i < l; i++) {
                if (children[i].isVisible()) {
                    return true;
                }
            }

            return false;
        };

        _proto._checkChildren = function _checkChildren() {
            var _this4 = this;

            var ids = {};
            this.layers.forEach(function(layer) {
                var layerId = layer.getId();

                if (ids[layerId]) {
                    throw new Error("Duplicate child layer id (" + layerId + ") in the GroupTileLayer (" + _this4.getId() + ")");
                } else {
                    ids[layerId] = 1;
                }
            });
        };

        return GroupTileLayer;
    }(TileLayer);

    GroupTileLayer.registerJSONType('GroupTileLayer');

    var options$v = {
        crs: null,
        uppercase: false,
        detectRetina: false
    };
    var defaultWmsParams = {
        service: 'WMS',
        request: 'GetMap',
        layers: '',
        styles: '',
        format: 'image/jpeg',
        transparent: false,
        version: '1.1.1'
    };

    var WMSTileLayer = function(_TileLayer) {
        _inheritsLoose(WMSTileLayer, _TileLayer);

        function WMSTileLayer(id, options) {
            var _this;

            _this = _TileLayer.call(this, id) || this;
            var wmsParams = extend({}, defaultWmsParams);

            for (var p in options) {
                if (!(p in _this.options)) {
                    wmsParams[p] = options[p];
                }
            }

            _this.setOptions(options);

            _this.setZIndex(options.zIndex);

            var tileSize = _this.getTileSize();

            wmsParams.width = tileSize.width;
            wmsParams.height = tileSize.height;
            _this.wmsParams = wmsParams;
            _this._wmsVersion = parseFloat(wmsParams.version);
            return _this;
        }

        var _proto = WMSTileLayer.prototype;

        _proto.onAdd = function onAdd() {
            var dpr = this.getMap().getDevicePixelRatio();
            var r = options$v.detectRetina ? dpr : 1;
            this.wmsParams.width *= r;
            this.wmsParams.height *= r;
            var crs = this.options.crs || this.getMap().getProjection().code;
            var projectionKey = this._wmsVersion >= 1.3 ? 'crs' : 'srs';
            this.wmsParams[projectionKey] = crs;

            _TileLayer.prototype.onAdd.call(this);
        };

        _proto.getTileUrl = function getTileUrl(x, y, z) {
            var res = this.getSpatialReference().getResolution(z),
                tileConfig = this._getTileConfig(),
                tileExtent = tileConfig.getTilePrjExtent(x, y, res);

            var max = tileExtent.getMax(),
                min = tileExtent.getMin();
            var bbox = (this._wmsVersion >= 1.3 && this.wmsParams.crs === 'EPSG:4326' ? [min.y, min.x, max.y, max.x] : [min.x, min.y, max.x, max.y]).join(',');

            var url = _TileLayer.prototype.getTileUrl.call(this, x, y, z);

            return url + getParamString(this.wmsParams, url, this.options.uppercase) + (this.options.uppercase ? '&BBOX=' : '&bbox=') + bbox;
        };

        _proto.toJSON = function toJSON() {
            return {
                'type': 'WMSTileLayer',
                'id': this.getId(),
                'options': this.config()
            };
        };

        WMSTileLayer.fromJSON = function fromJSON(layerJSON) {
            if (!layerJSON || layerJSON['type'] !== 'WMSTileLayer') {
                return null;
            }

            return new WMSTileLayer(layerJSON['id'], layerJSON['options']);
        };

        return WMSTileLayer;
    }(TileLayer);

    WMSTileLayer.registerJSONType('WMSTileLayer');
    WMSTileLayer.mergeOptions(options$v);

    function getParamString(obj, existingUrl, uppercase) {
        var params = [];

        for (var i in obj) {
            params.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i]));
        }

        return (!existingUrl || existingUrl.indexOf('?') === -1 ? '?' : '&') + params.join('&');
    }

    var CanvasTileLayer = function(_TileLayer) {
        _inheritsLoose(CanvasTileLayer, _TileLayer);

        function CanvasTileLayer(id, options) {
            var _this;

            _this = _TileLayer.call(this, id, options) || this;

            if (!_this.options.hasOwnProperty('forceRenderOnMoving')) {
                _this.options['forceRenderOnMoving'] = false;
            }

            return _this;
        }

        var _proto = CanvasTileLayer.prototype;

        _proto.drawTile = function drawTile() {};

        _proto.toJSON = function toJSON() {
            return {
                'type': 'CanvasTileLayer',
                'id': this.getId(),
                'options': this.config()
            };
        };

        CanvasTileLayer.fromJSON = function fromJSON(layerJSON) {
            if (!layerJSON || layerJSON['type'] !== 'CanvasTileLayer') {
                return null;
            }

            return new CanvasTileLayer(layerJSON['id'], layerJSON['options']);
        };

        return CanvasTileLayer;
    }(TileLayer);

    CanvasTileLayer.registerJSONType('CanvasTileLayer');

    function createGLContext(canvas, options) {
        var attributes = {
            'alpha': true,
            'stencil': true,
            'preserveDrawingBuffer': true,
            'antialias': false
        };
        var names = ['webgl', 'experimental-webgl'];
        var context = null;

        for (var i = 0; i < names.length; ++i) {
            try {
                context = canvas.getContext(names[i], options || attributes);
            } catch (e) {}

            if (context) {
                break;
            }
        }

        return context;
    }

    function compileShader(gl, type, source) {
        var shader = gl.createShader(type);
        gl.shaderSource(shader, source);
        gl.compileShader(shader);
        var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);

        if (!compiled) {
            var error = gl.getShaderInfoLog(shader);
            gl.deleteShader(shader);
            throw new Error('Failed to compile shader: ' + error);
        }

        return shader;
    }

    function createProgram(gl, vert, frag) {
        var vertexShader = compileShader(gl, gl.VERTEX_SHADER, vert);
        var fragmentShader = compileShader(gl, gl.FRAGMENT_SHADER, frag);

        if (!vertexShader || !fragmentShader) {
            return null;
        }

        var program = gl.createProgram();

        if (!program) {
            return null;
        }

        gl.attachShader(program, vertexShader);
        gl.attachShader(program, fragmentShader);
        gl.linkProgram(program);
        return {
            program: program,
            vertexShader: vertexShader,
            fragmentShader: fragmentShader
        };
    }

    function enableVertexAttrib(gl, program, attributes) {
        if (Array.isArray(attributes[0])) {
            var FSIZE = Float32Array.BYTES_PER_ELEMENT;
            var STRIDE = 0;

            for (var i = 0; i < attributes.length; i++) {
                STRIDE += attributes[i][1] || 0;
            }

            var offset = 0;

            for (var _i = 0; _i < attributes.length; _i++) {
                var attr = gl.getAttribLocation(program, attributes[_i][0]);

                if (attr < 0) {
                    throw new Error('Failed to get the storage location of ' + attributes[_i][0]);
                }

                gl.vertexAttribPointer(attr, attributes[_i][1], gl[attributes[_i][2] || 'FLOAT'], false, FSIZE * STRIDE, FSIZE * offset);
                offset += attributes[_i][1] || 0;
                gl.enableVertexAttribArray(attr);
            }
        } else {
            var _attr = gl.getAttribLocation(program, attributes[0]);

            gl.vertexAttribPointer(_attr, attributes[1], gl[attributes[2] || 'FLOAT'], false, 0, 0);
            gl.enableVertexAttribArray(_attr);
        }
    }

    var shaders = {
        'vertexShader': "\n        attribute vec2 a_position;\n\n        attribute vec2 a_texCoord;\n\n        uniform mat4 u_matrix;\n\n        varying vec2 v_texCoord;\n\n        void main() {\n            gl_Position = u_matrix * vec4(a_position, 0., 1.);\n\n            v_texCoord = a_texCoord;\n        }\n    ",
        'fragmentShader': "\n        precision mediump float;\n\n        uniform sampler2D u_image;\n\n        uniform float u_opacity;\n        uniform float u_debug_line;\n\n        varying vec2 v_texCoord;\n\n        void main() {\n            if (u_debug_line == 1.) {\n                gl_FragColor = vec4(0., 1., 0., 1.);\n            } else {\n                gl_FragColor = texture2D(u_image, v_texCoord) * u_opacity;\n            }\n        }\n    "
    };
    var v2 = [0, 0],
        v3 = [0, 0, 0],
        arr16 = new Array(16);
    var DEBUG_POINT = new Point(20, 20);

    var ImageGLRenderable = function ImageGLRenderable(Base) {
        var renderable = function(_Base) {
            _inheritsLoose(renderable, _Base);

            function renderable() {
                return _Base.apply(this, arguments) || this;
            }

            var _proto = renderable.prototype;

            _proto.drawGLImage = function drawGLImage(image, x, y, w, h, scale$$1, opacity, debug) {
                if (this.gl.program !== this.program) {
                    this.useProgram(this.program);
                }

                var gl = this.gl;
                this.loadTexture(image);
                v3[0] = x || 0;
                v3[1] = y || 0;
                var uMatrix = identity(arr16);
                translate(uMatrix, uMatrix, v3);
                scale(uMatrix, uMatrix, [scale$$1, scale$$1, 1]);
                multiply(uMatrix, this.getMap().projViewMatrix, uMatrix);
                gl.uniformMatrix4fv(this.program['u_matrix'], false, uMatrix);
                gl.uniform1f(this.program['u_opacity'], opacity);
                gl.uniform1f(this.program['u_debug_line'], 0);
                var glBuffer = image.glBuffer;

                if (glBuffer && (glBuffer.width !== w || glBuffer.height !== h)) {
                    this.saveImageBuffer(glBuffer);
                    delete image.glBuffer;
                }

                if (!image.glBuffer) {
                    image.glBuffer = this.bufferTileData(0, 0, w, h);
                } else {
                    gl.bindBuffer(gl.ARRAY_BUFFER, glBuffer);
                }

                v2[0] = 'a_position';
                v2[1] = 2;
                v2[2] = image.glBuffer.type;
                this.enableVertexAttrib(v2);
                gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);

                if (debug) {
                    this.drawDebug(uMatrix, v2, 0, 0, w, h, debug);
                }
            };

            _proto.drawDebug = function drawDebug(uMatrix, attrib, x, y, w, h, debugInfo) {
                var gl = this.gl;
                gl.bindBuffer(gl.ARRAY_BUFFER, this._debugBuffer);
                this.enableVertexAttrib(['a_position', 2, 'FLOAT']);
                gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([x, y, x + w, y, x + w, y - h, x, y - h, x, y]), gl.DYNAMIC_DRAW);
                gl.uniformMatrix4fv(this.program['u_matrix'], false, uMatrix);
                gl.uniform1f(this.program['u_debug_line'], 1);
                gl.drawArrays(gl.LINE_STRIP, 0, 5);
                var canvas = this._debugInfoCanvas;

                if (!canvas) {
                    var dpr = this.getMap().getDevicePixelRatio() > 1 ? 2 : 1;
                    canvas = this._debugInfoCanvas = document.createElement('canvas');
                    canvas.width = 256 * dpr;
                    canvas.height = 32 * dpr;

                    var _ctx = canvas.getContext('2d');

                    _ctx.font = '20px monospace';

                    _ctx.scale(dpr, dpr);
                }

                var ctx = canvas.getContext('2d');
                ctx.clearRect(0, 0, canvas.width, canvas.height);
                var color = this.layer.options['debugOutline'];
                Canvas.fillText(ctx, debugInfo, DEBUG_POINT, color);
                this.loadTexture(canvas);
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas);
                w = 256;
                h = 32;
                var x1 = x;
                var x2 = x + w;
                var y1 = y;
                var y2 = y - h;
                gl.bufferData(gl.ARRAY_BUFFER, this.set8(x1, y1, x1, y2, x2, y1, x2, y2), gl.DYNAMIC_DRAW);
                gl.uniform1f(this.program['u_debug_line'], 0);
                gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
            };

            _proto.bufferTileData = function bufferTileData(x, y, w, h, buffer) {
                var x1 = x;
                var x2 = x + w;
                var y1 = y;
                var y2 = y - h;
                var data;

                if (isInteger(x1) && isInteger(x2) && isInteger(y1) && isInteger(y2)) {
                    data = this.set8Int(x1, y1, x1, y2, x2, y1, x2, y2);
                } else {
                    data = this.set8(x1, y1, x1, y2, x2, y1, x2, y2);
                }

                var glBuffer = this.loadImageBuffer(data, buffer);
                glBuffer.width = w;
                glBuffer.height = h;
                glBuffer.type = data instanceof Int16Array ? 'SHORT' : 'FLOAT';
                return glBuffer;
            };

            _proto.drawTinImage = function drawTinImage(image, vertices, texCoords, indices, opacity) {
                var gl = this.gl;
                this.loadTexture(image);
                gl.uniformMatrix4fv(this.program['u_matrix'], false, this.getMap().projViewMatrix);
                gl.uniform1f(this.program['u_opacity'], opacity);
                gl.bindBuffer(gl.ARRAY_BUFFER, this.posBuffer);
                this.enableVertexAttrib(['a_position', 3]);
                gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.DYNAMIC_DRAW);
                gl.bindBuffer(gl.ARRAY_BUFFER, this.texBuffer);
                this.enableVertexAttrib(['a_texCoord', 2]);
                gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(texCoords), gl.DYNAMIC_DRAW);
                gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.DYNAMIC_DRAW);
                gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
            };

            _proto.createCanvas2 = function createCanvas2() {
                this.canvas2 = Canvas.createCanvas(this.canvas.width, this.canvas.height);
            };

            _proto.createGLContext = function createGLContext$$1() {
                if (this.canvas.gl && this.canvas.gl.wrap) {
                    this.gl = this.canvas.gl.wrap();
                } else {
                    this.gl = createGLContext(this.canvas2 || this.canvas, this.layer.options['glOptions']);
                }

                var gl = this.gl;
                gl.clearColor(0.0, 0.0, 0.0, 0.0);
                gl.disable(gl.DEPTH_TEST);
                gl.enable(gl.STENCIL_TEST);
                gl.enable(gl.BLEND);
                gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
                this.program = this.createProgram(shaders['vertexShader'], this.layer.options['fragmentShader'] || shaders['fragmentShader'], ['u_matrix', 'u_image', 'u_opacity', 'u_debug_line']);
                this._debugBuffer = this.createBuffer();
                this.useProgram(this.program);
                this.texBuffer = this.createBuffer();
                gl.bindBuffer(gl.ARRAY_BUFFER, this.texBuffer);
                this.enableVertexAttrib(['a_texCoord', 2, 'UNSIGNED_BYTE']);
                gl.bufferData(gl.ARRAY_BUFFER, new Uint8Array([0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0]), gl.STATIC_DRAW);
                this.enableSampler('u_image');
                gl.activeTexture(gl['TEXTURE0']);
                gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
            };

            _proto.resizeGLCanvas = function resizeGLCanvas() {
                if (this.gl) {
                    this.gl.viewport(0, 0, this.canvas.width, this.canvas.height);
                }

                if (!this.canvas2) {
                    return;
                }

                if (this.canvas2.width !== this.canvas.width || this.canvas2.height !== this.canvas.height) {
                    this.canvas2.width = this.canvas.width;
                    this.canvas2.height = this.canvas.height;
                }
            };

            _proto.clearGLCanvas = function clearGLCanvas() {
                if (this.gl) {
                    this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.STENCIL_BUFFER_BIT);
                }
            };

            _proto.disposeImage = function disposeImage(image) {
                if (!image) {
                    return;
                }

                if (image.texture) {
                    this.saveTexture(image.texture);
                }

                if (image.glBuffer) {
                    this.saveImageBuffer(image.glBuffer);
                }

                delete image.texture;
                delete image.glBuffer;
            };

            _proto._createTexture = function _createTexture(image) {
                var gl = this.gl;
                var texture = this.getTexture() || gl.createTexture();
                gl.bindTexture(gl.TEXTURE_2D, texture);
                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);

                if (isInteger(log2(image.width)) && isInteger(log2(image.width))) {
                    gl.generateMipmap(gl.TEXTURE_2D);
                }

                return texture;
            };

            _proto.getTexture = function getTexture() {
                if (!this._textures) {
                    this._textures = [];
                }

                var textures = this._textures;
                return textures && textures.length > 0 ? textures.pop() : null;
            };

            _proto.saveTexture = function saveTexture(texture) {
                this._textures.push(texture);
            };

            _proto.loadTexture = function loadTexture(image) {
                var gl = this.gl;
                var texture = image.texture;

                if (!texture) {
                    texture = this._createTexture(image);
                    image.texture = texture;
                }

                gl.bindTexture(gl.TEXTURE_2D, texture);
                return texture;
            };

            _proto.getImageBuffer = function getImageBuffer() {
                if (!this._imageBuffers) {
                    this._imageBuffers = [];
                }

                var imageBuffers = this._imageBuffers;
                return imageBuffers && imageBuffers.length > 0 ? imageBuffers.pop() : null;
            };

            _proto.saveImageBuffer = function saveImageBuffer(buffer) {
                this._imageBuffers.push(buffer);
            };

            _proto.loadImageBuffer = function loadImageBuffer(data, glBuffer) {
                var gl = this.gl;
                var buffer = glBuffer || this.createImageBuffer();
                gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
                gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
                return buffer;
            };

            _proto.createImageBuffer = function createImageBuffer() {
                return this.getImageBuffer() || this.createBuffer();
            };

            _proto.removeGLCanvas = function removeGLCanvas() {
                var gl = this.gl;

                if (!gl) {
                    return;
                }

                if (this._debugBuffer) {
                    gl.deleteBuffer(this._debugBuffer);
                    delete this._debugBuffer;
                }

                if (this._buffers) {
                    this._buffers.forEach(function(b) {
                        gl.deleteBuffer(b);
                    });

                    delete this._buffers;
                }

                if (this._textures) {
                    this._textures.forEach(function(t) {
                        return gl.deleteTexture(t);
                    });

                    delete this._textures;
                }

                if (this._debugInfoCanvas) {
                    var texture = this._debugInfoCanvas.texture;

                    if (texture) {
                        gl.deleteTexture(texture);
                    }

                    delete this._debugInfoCanvas.texture;
                    delete this._debugInfoCanvas;
                }

                var program = gl.program;
                gl.deleteShader(program.fragmentShader);
                gl.deleteShader(program.vertexShader);
                gl.deleteProgram(program);
                delete this.gl;
                delete this.canvas2;
            };

            _proto.createBuffer = function createBuffer() {
                var gl = this.gl;
                var buffer = gl.createBuffer();

                if (!buffer) {
                    throw new Error('Failed to create the buffer object');
                }

                if (!this._buffers) {
                    this._buffers = [];
                }

                this._buffers.push(buffer);

                return buffer;
            };

            _proto.enableVertexAttrib = function enableVertexAttrib$$1(attributes) {
                enableVertexAttrib(this.gl, this.gl.program, attributes);
            };

            _proto.createProgram = function createProgram$$1(vert, frag, uniforms) {
                var gl = this.gl;

                var _createProgram2 = createProgram(gl, vert, frag),
                    program = _createProgram2.program,
                    vertexShader = _createProgram2.vertexShader,
                    fragmentShader = _createProgram2.fragmentShader;

                program.vertexShader = vertexShader;
                program.fragmentShader = fragmentShader;

                this._initUniforms(program, uniforms);

                return program;
            };

            _proto.useProgram = function useProgram(program) {
                var gl = this.gl;
                gl.useProgram(program);
                gl.program = program;
                return this;
            };

            _proto.enableSampler = function enableSampler(sampler, texIdx) {
                var gl = this.gl;

                var uSampler = this._getUniform(gl.program, sampler);

                if (!texIdx) {
                    texIdx = 0;
                }

                gl.uniform1i(uSampler, texIdx);
                return uSampler;
            };

            _proto._initUniforms = function _initUniforms(program, uniforms) {
                for (var i = 0; i < uniforms.length; i++) {
                    var name = uniforms[i];
                    var uniform = uniforms[i];
                    var b = name.indexOf('[');

                    if (b >= 0) {
                        name = name.substring(0, b);

                        if (!IS_NODE) {
                            uniform = uniform.substring(0, b);
                        }
                    }

                    program[name] = this._getUniform(program, uniform);
                }
            };

            _proto._getUniform = function _getUniform(program, uniformName) {
                var gl = this.gl;
                var uniform = gl.getUniformLocation(program, uniformName);

                if (!uniform) {
                    throw new Error('Failed to get the storage location of ' + uniformName);
                }

                return uniform;
            };

            return renderable;
        }(Base);

        extend(renderable.prototype, {
            set8: function() {
                var out = Browser$1.ie9 ? null : new Float32Array(8);
                return function(a0, a1, a2, a3, a4, a5, a6, a7) {
                    out[0] = a0;
                    out[1] = a1;
                    out[2] = a2;
                    out[3] = a3;
                    out[4] = a4;
                    out[5] = a5;
                    out[6] = a6;
                    out[7] = a7;
                    return out;
                };
            }(),
            set8Int: function() {
                var out = Browser$1.ie9 ? null : new Int16Array(8);
                return function(a0, a1, a2, a3, a4, a5, a6, a7) {
                    out[0] = a0;
                    out[1] = a1;
                    out[2] = a2;
                    out[3] = a3;
                    out[4] = a4;
                    out[5] = a5;
                    out[6] = a6;
                    out[7] = a7;
                    return out;
                };
            }()
        });
        return renderable;
    };

    var options$w = {
        renderer: Browser$1.webgl ? 'gl' : 'canvas',
        crossOrigin: null
    };
    var TEMP_POINT$1 = new Point(0, 0);

    var ImageLayer = function(_Layer) {
        _inheritsLoose(ImageLayer, _Layer);

        function ImageLayer(id, images, options) {
            var _this;

            if (images && !Array.isArray(images) && !images.url) {
                options = images;
                images = null;
            }

            _this = _Layer.call(this, id, options) || this;
            _this._images = images;
            return _this;
        }

        var _proto = ImageLayer.prototype;

        _proto.onAdd = function onAdd() {
            this._prepareImages(this._images);
        };

        _proto.setImages = function setImages(images) {
            this._images = images;

            this._prepareImages(images);

            return this;
        };

        _proto.getImages = function getImages() {
            return this._images;
        };

        _proto._prepareImages = function _prepareImages(images) {
            images = images || [];

            if (!Array.isArray(images)) {
                images = [images];
            }

            var map = this.getMap();
            this._imageData = images.map(function(img) {
                var extent = new Extent(img.extent);
                return extend({}, img, {
                    extent: extent,
                    extent2d: extent.convertTo(function(c) {
                        return map.coordToPoint(c, map.getGLZoom());
                    })
                });
            });
            this._images = images;
            var renderer = this.getRenderer();

            if (renderer) {
                renderer.refreshImages();
            }
        };

        return ImageLayer;
    }(Layer);

    ImageLayer.mergeOptions(options$w);
    var EMPTY_ARRAY = [];
    var ImageLayerCanvasRenderer = function(_CanvasRenderer) {
        _inheritsLoose(ImageLayerCanvasRenderer, _CanvasRenderer);

        function ImageLayerCanvasRenderer() {
            return _CanvasRenderer.apply(this, arguments) || this;
        }

        var _proto2 = ImageLayerCanvasRenderer.prototype;

        _proto2.isDrawable = function isDrawable() {
            if (this.getMap().getPitch()) {
                if (console) {
                    console.warn('ImageLayer with canvas renderer can\'t be pitched, use gl renderer (\'renderer\' : \'gl\') instead.');
                }

                return false;
            }

            return true;
        };

        _proto2.checkResources = function checkResources() {
            var _this2 = this;

            if (this._imageLoaded) {
                return EMPTY_ARRAY;
            }

            var layer = this.layer;

            var urls = layer._imageData.map(function(img) {
                return [img.url, null, null];
            });

            if (this.resources) {
                var unloaded = [];
                var resources = new ResourceCache();
                urls.forEach(function(url) {
                    if (_this2.resources.isResourceLoaded(url)) {
                        var img = _this2.resources.getImage(url);

                        resources.addResource(url, img);
                    } else {
                        unloaded.push(url);
                    }
                });
                this.resources.forEach(function(url, res) {
                    if (!resources.isResourceLoaded(url)) {
                        _this2.retireImage(res.image);
                    }
                });
                this.resources = resources;
                urls = unloaded;
            }

            this._imageLoaded = true;
            return urls;
        };

        _proto2.retireImage = function retireImage() {};

        _proto2.refreshImages = function refreshImages() {
            this._imageLoaded = false;
            this.setToRedraw();
        };

        _proto2.needToRedraw = function needToRedraw() {
            var map = this.getMap();

            if (map.isZooming() && !map.getPitch()) {
                return false;
            }

            return _CanvasRenderer.prototype.needToRedraw.call(this);
        };

        _proto2.draw = function draw() {
            if (!this.isDrawable()) {
                return;
            }

            this.prepareCanvas();
            this._painted = false;

            this._drawImages();

            this.completeRender();
        };

        _proto2._drawImages = function _drawImages() {
            var imgData = this.layer._imageData;
            var map = this.getMap();

            var mapExtent = map._get2DExtent(map.getGLZoom());

            if (imgData && imgData.length) {
                for (var i = 0; i < imgData.length; i++) {
                    var extent = imgData[i].extent2d;
                    var image = this.resources && this.resources.getImage(imgData[i].url);

                    if (image && mapExtent.intersects(extent)) {
                        this._painted = true;

                        this._drawImage(image, extent, imgData[i].opacity || 1);
                    }
                }
            }
        };

        _proto2._drawImage = function _drawImage(image, extent, opacity) {
            var globalAlpha = 0;
            var ctx = this.context;

            if (opacity < 1) {
                globalAlpha = ctx.globalAlpha;
                ctx.globalAlpha = opacity;
            }

            var map = this.getMap();
            var nw = TEMP_POINT$1.set(extent.xmin, extent.ymax);

            var point = map._pointToContainerPoint(nw, map.getGLZoom());

            var x = point.x,
                y = point.y;
            var bearing = map.getBearing();

            if (bearing) {
                ctx.save();
                ctx.translate(x, y);

                if (bearing) {
                    ctx.rotate(-bearing * Math.PI / 180);
                }

                x = y = 0;
            }

            var scale = map.getGLScale();
            ctx.drawImage(image, x, y, extent.getWidth() / scale, extent.getHeight() / scale);

            if (bearing) {
                ctx.restore();
            }

            if (globalAlpha) {
                ctx.globalAlpha = globalAlpha;
            }
        };

        _proto2.drawOnInteracting = function drawOnInteracting() {
            this.draw();
        };

        return ImageLayerCanvasRenderer;
    }(CanvasRenderer);
    var ImageLayerGLRenderer = function(_ImageGLRenderable) {
        _inheritsLoose(ImageLayerGLRenderer, _ImageGLRenderable);

        function ImageLayerGLRenderer() {
            return _ImageGLRenderable.apply(this, arguments) || this;
        }

        var _proto3 = ImageLayerGLRenderer.prototype;

        _proto3.isDrawable = function isDrawable() {
            return true;
        };

        _proto3._drawImage = function _drawImage(image, extent, opacity) {
            this.drawGLImage(image, extent.xmin, extent.ymax, extent.getWidth(), extent.getHeight(), 1, opacity);
        };

        _proto3.createContext = function createContext() {
            this.createGLContext();
        };

        _proto3.resizeCanvas = function resizeCanvas(canvasSize) {
            if (!this.canvas) {
                return;
            }

            _ImageGLRenderable.prototype.resizeCanvas.call(this, canvasSize);

            this.resizeGLCanvas();
        };

        _proto3.clearCanvas = function clearCanvas() {
            if (!this.canvas) {
                return;
            }

            _ImageGLRenderable.prototype.clearCanvas.call(this);

            this.clearGLCanvas();
        };

        _proto3.retireImage = function retireImage(image) {
            this.disposeImage(image);
        };

        _proto3.onRemove = function onRemove() {
            this.removeGLCanvas();

            _ImageGLRenderable.prototype.onRemove.call(this);
        };

        return ImageLayerGLRenderer;
    }(ImageGLRenderable(ImageLayerCanvasRenderer));
    ImageLayer.registerRenderer('canvas', ImageLayerCanvasRenderer);
    ImageLayer.registerRenderer('gl', ImageLayerGLRenderer);

    var CanvasLayerRenderer = function(_CanvasRenderer) {
        _inheritsLoose(CanvasLayerRenderer, _CanvasRenderer);

        function CanvasLayerRenderer() {
            return _CanvasRenderer.apply(this, arguments) || this;
        }

        var _proto = CanvasLayerRenderer.prototype;

        _proto.getPrepareParams = function getPrepareParams() {
            return [];
        };

        _proto.getDrawParams = function getDrawParams() {
            return [];
        };

        _proto.onCanvasCreate = function onCanvasCreate() {
            if (this.canvas && this.layer.options['doubleBuffer']) {
                this.buffer = Canvas.createCanvas(this.canvas.width, this.canvas.height, this.getMap().CanvasClass);
            }
        };

        _proto.needToRedraw = function needToRedraw() {
            if (this.layer.options['animation']) {
                return true;
            }

            var map = this.getMap();

            if (map.isInteracting() && !this.layer.drawOnInteracting) {
                return false;
            }

            return _CanvasRenderer.prototype.needToRedraw.call(this);
        };

        _proto.draw = function draw() {
            this.prepareCanvas();
            this.prepareDrawContext();

            this._drawLayer();
        };

        _proto.drawOnInteracting = function drawOnInteracting() {
            this._drawLayerOnInteracting();
        };

        _proto.getCanvasImage = function getCanvasImage() {
            var canvasImg = _CanvasRenderer.prototype.getCanvasImage.call(this);

            if (canvasImg && canvasImg.image && this.layer.options['doubleBuffer']) {
                var canvas = canvasImg.image;

                if (this.buffer.width !== canvas.width || this.buffer.height !== canvas.height) {
                    this.buffer.width = canvas.width;
                    this.buffer.height = canvas.height;
                }

                var bufferContext = this.buffer.getContext('2d');
                var prevent = this.layer.doubleBuffer(bufferContext, this.context);

                if (prevent === undefined || prevent) {
                    Canvas.image(bufferContext, canvas, 0, 0);
                    canvasImg.image = this.buffer;
                }
            }

            return canvasImg;
        };

        _proto.remove = function remove() {
            delete this._drawContext;
            return _CanvasRenderer.prototype.remove.call(this);
        };

        _proto.onZoomStart = function onZoomStart(param) {
            this.layer.onZoomStart(param);

            _CanvasRenderer.prototype.onZoomStart.call(this, param);
        };

        _proto.onZooming = function onZooming(param) {
            this.layer.onZooming(param);

            _CanvasRenderer.prototype.onZooming.call(this, param);
        };

        _proto.onZoomEnd = function onZoomEnd(param) {
            this.layer.onZoomEnd(param);

            _CanvasRenderer.prototype.onZoomEnd.call(this, param);
        };

        _proto.onMoveStart = function onMoveStart(param) {
            this.layer.onMoveStart(param);

            _CanvasRenderer.prototype.onMoveStart.call(this, param);
        };

        _proto.onMoving = function onMoving(param) {
            this.layer.onMoving(param);

            _CanvasRenderer.prototype.onMoving.call(this, param);
        };

        _proto.onMoveEnd = function onMoveEnd(param) {
            this.layer.onMoveEnd(param);

            _CanvasRenderer.prototype.onMoveEnd.call(this, param);
        };

        _proto.onResize = function onResize(param) {
            this.layer.onResize(param);

            _CanvasRenderer.prototype.onResize.call(this, param);
        };

        _proto.prepareDrawContext = function prepareDrawContext() {
            if (!this._predrawed) {
                var params = ensureParams(this.getPrepareParams());
                this._drawContext = this.layer.prepareToDraw.apply(this.layer, [this.context].concat(params));

                if (!this._drawContext) {
                    this._drawContext = [];
                }

                if (!Array.isArray(this._drawContext)) {
                    this._drawContext = [this._drawContext];
                }

                this._predrawed = true;
            }
        };

        _proto._prepareDrawParams = function _prepareDrawParams() {
            if (!this.getMap()) {
                return null;
            }

            var view = this.getViewExtent();

            if (view['maskExtent'] && !view['extent'].intersects(view['maskExtent'])) {
                this.completeRender();
                return null;
            }

            var args = [this.context, view];
            var params = ensureParams(this.getDrawParams());
            args.push.apply(args, params);
            args.push.apply(args, this._drawContext);
            return args;
        };

        _proto._drawLayer = function _drawLayer() {
            var args = this._prepareDrawParams();

            if (!args) {
                return;
            }

            this.layer.draw.apply(this.layer, args);
            this.completeRender();
        };

        _proto._drawLayerOnInteracting = function _drawLayerOnInteracting() {
            if (!this.layer.drawOnInteracting) {
                return;
            }

            var args = this._prepareDrawParams();

            if (!args) {
                return;
            }

            this.layer.drawOnInteracting.apply(this.layer, args);
            this.completeRender();
        };

        return CanvasLayerRenderer;
    }(CanvasRenderer);

    function ensureParams(params) {
        if (!params) {
            params = [];
        }

        if (!Array.isArray(params)) {
            params = [params];
        }

        return params;
    }

    var options$x = {
        'doubleBuffer': false,
        'animation': false
    };

    var CanvasLayer = function(_Layer) {
        _inheritsLoose(CanvasLayer, _Layer);

        function CanvasLayer() {
            return _Layer.apply(this, arguments) || this;
        }

        var _proto = CanvasLayer.prototype;

        _proto.isCanvasRender = function isCanvasRender() {
            return true;
        };

        _proto.prepareToDraw = function prepareToDraw() {};

        _proto.draw = function draw() {};

        _proto.redraw = function redraw() {
            if (this._getRenderer()) {
                this._getRenderer().setToRedraw();
            }

            return this;
        };

        _proto.play = function play() {
            this.config('animation', true);
            return this;
        };

        _proto.pause = function pause() {
            this.config('animation', false);
            return this;
        };

        _proto.isPlaying = function isPlaying() {
            return this.options['animation'];
        };

        _proto.clearCanvas = function clearCanvas() {
            if (this._getRenderer()) {
                this._getRenderer().clearCanvas();
            }

            return this;
        };

        _proto.requestMapToRender = function requestMapToRender() {
            if (this._getRenderer()) {
                this._getRenderer().requestMapToRender();
            }

            return this;
        };

        _proto.completeRender = function completeRender() {
            if (this._getRenderer()) {
                this._getRenderer().completeRender();
            }

            return this;
        };

        _proto.onCanvasCreate = function onCanvasCreate() {
            return this;
        };

        _proto.onZoomStart = function onZoomStart() {};

        _proto.onZooming = function onZooming() {};

        _proto.onZoomEnd = function onZoomEnd() {};

        _proto.onMoveStart = function onMoveStart() {};

        _proto.onMoving = function onMoving() {};

        _proto.onMoveEnd = function onMoveEnd() {};

        _proto.onResize = function onResize() {};

        _proto.doubleBuffer = function doubleBuffer(bufferContext) {
            bufferContext.clearRect(0, 0, bufferContext.canvas.width, bufferContext.canvas.height);
            return this;
        };

        return CanvasLayer;
    }(Layer);

    CanvasLayer.mergeOptions(options$x);
    CanvasLayer.registerRenderer('canvas', CanvasLayerRenderer);

    var TEMP_POINT$2 = new Point(0, 0);
    var options$y = {
        'animation': true
    };

    var ParticleLayer = function(_CanvasLayer) {
        _inheritsLoose(ParticleLayer, _CanvasLayer);

        function ParticleLayer() {
            return _CanvasLayer.apply(this, arguments) || this;
        }

        var _proto = ParticleLayer.prototype;

        _proto.getParticles = function getParticles() {};

        _proto.draw = function draw(context, view) {
            var points = this.getParticles(now());

            if (!points || points.length === 0) {
                var renderer = this._getRenderer();

                if (renderer) {
                    this._getRenderer()._shouldClear = true;
                }

                return;
            }

            var map = this.getMap();
            var extent = view.extent;

            if (view.maskExtent) {
                extent = view.extent.intersection(view.maskExtent);
            }

            extent = extent.convertTo(function(c) {
                return map._pointToContainerPoint(c, undefined, 0, TEMP_POINT$2);
            });
            var e = 2 * Math.PI;

            for (var i = 0, l = points.length; i < l; i++) {
                var pos = points[i].point;

                if (extent.contains(pos)) {
                    var color = points[i].color || this.options['lineColor'] || '#fff',
                        r = points[i].r;

                    if (context.fillStyle !== color) {
                        context.fillStyle = color;
                    }

                    if (r <= 2) {
                        context.fillRect(pos.x - r / 2, pos.y - r / 2, r, r);
                    } else {
                        context.beginPath();
                        context.arc(pos.x, pos.y, r / 2, 0, e);
                        context.fill();
                    }
                }
            }

            this._fillCanvas(context);
        };

        _proto._fillCanvas = function _fillCanvas(context) {
            var g = context.globalCompositeOperation;
            context.globalCompositeOperation = 'destination-out';
            var trail = this.options['trail'] || 30;
            context.fillStyle = 'rgba(0, 0, 0, ' + 1 / trail + ')';
            context.fillRect(0, 0, context.canvas.width, context.canvas.height);
            context.globalCompositeOperation = g;
        };

        return ParticleLayer;
    }(CanvasLayer);

    ParticleLayer.mergeOptions(options$y);
    ParticleLayer.registerRenderer('canvas', function(_CanvasLayerRenderer) {
        _inheritsLoose(_class, _CanvasLayerRenderer);

        function _class() {
            return _CanvasLayerRenderer.apply(this, arguments) || this;
        }

        var _proto2 = _class.prototype;

        _proto2.draw = function draw() {
            if (!this.canvas || !this.layer.options['animation'] || this._shouldClear) {
                this.prepareCanvas();
                this._shouldClear = false;
            }

            this.prepareDrawContext();

            this._drawLayer();
        };

        _proto2.drawOnInteracting = function drawOnInteracting() {
            this.draw();
            this._shouldClear = false;
        };

        _proto2.onSkipDrawOnInteracting = function onSkipDrawOnInteracting() {
            this._shouldClear = true;
        };

        return _class;
    }(CanvasLayerRenderer));

    var EDIT_STAGE_LAYER_PREFIX = INTERNAL_LAYER_PREFIX + '_edit_stage_';

    function createHandleSymbol(markerType, opacity) {
        return {
            'markerType': markerType,
            'markerFill': '#fff',
            'markerLineColor': '#000',
            'markerLineWidth': 2,
            'markerWidth': 10,
            'markerHeight': 10,
            'opacity': opacity
        };
    }

    var options$z = {
        'fixAspectRatio': false,
        'symbol': null,
        'removeVertexOn': 'contextmenu',
        'centerHandleSymbol': createHandleSymbol('ellipse', 1),
        'vertexHandleSymbol': createHandleSymbol('square', 1),
        'newVertexHandleSymbol': createHandleSymbol('square', 0.4)
    };

    var GeometryEditor = function(_Eventable) {
        _inheritsLoose(GeometryEditor, _Eventable);

        function GeometryEditor(geometry, opts) {
            var _this;

            _this = _Eventable.call(this, opts) || this;
            _this._geometry = geometry;

            if (!_this._geometry) {
                return _assertThisInitialized(_this);
            }

            return _this;
        }

        var _proto = GeometryEditor.prototype;

        _proto.getMap = function getMap() {
            return this._geometry.getMap();
        };

        _proto.prepare = function prepare() {
            var map = this.getMap();

            if (!map) {
                return;
            }

            if (this.options['symbol']) {
                this._originalSymbol = this._geometry.getSymbol();

                this._geometry.setSymbol(this.options['symbol']);
            }

            this._prepareEditStageLayer();
        };

        _proto._prepareEditStageLayer = function _prepareEditStageLayer() {
            var map = this.getMap();
            var uid = UID();
            var stageId = EDIT_STAGE_LAYER_PREFIX + uid,
                shadowId = EDIT_STAGE_LAYER_PREFIX + uid + '_shadow';
            this._editStageLayer = map.getLayer(stageId);
            this._shadowLayer = map.getLayer(shadowId);

            if (!this._editStageLayer) {
                this._editStageLayer = new VectorLayer(stageId);
                map.addLayer(this._editStageLayer);
            }

            if (!this._shadowLayer) {
                this._shadowLayer = new VectorLayer(shadowId);
                map.addLayer(this._shadowLayer);
            }
        };

        _proto.start = function start() {
            var _this2 = this;

            if (!this._geometry || !this._geometry.getMap() || this._geometry.editing) {
                return;
            }

            var map = this.getMap();
            this.editing = true;
            var geometry = this._geometry;
            this._geometryDraggble = geometry.options['draggable'];
            geometry.config('draggable', false);
            this.prepare();
            var shadow = geometry.copy();
            shadow.setSymbol(geometry._getInternalSymbol());
            shadow.copyEventListeners(geometry);

            if (geometry._getParent()) {
                shadow.copyEventListeners(geometry._getParent());
            }

            shadow._setEventTarget(geometry);

            shadow.setId(null).config({
                'draggable': false
            });
            this._shadow = shadow;

            this._switchGeometryEvents('on');

            geometry.hide();

            if (geometry instanceof Marker || geometry instanceof Circle || geometry instanceof Rectangle || geometry instanceof Ellipse) {
                this._createOrRefreshOutline();
            }

            this._shadowLayer.bringToFront().addGeometry(shadow);

            this._editStageLayer.bringToFront();

            this._addListener([map, 'zoomstart', function() {
                _this2._editStageLayer.hide();
            }]);

            this._addListener([map, 'zoomend', function() {
                _this2._editStageLayer.show();
            }]);

            if (!(geometry instanceof Marker)) {
                this._createCenterHandle();
            } else {
                shadow.config('draggable', true);
                shadow.on('dragend', this._onMarkerDragEnd, this);
            }

            if (geometry instanceof Marker) {
                this.createMarkerEditor();
            } else if (geometry instanceof Circle) {
                this.createCircleEditor();
            } else if (geometry instanceof Rectangle) {
                this.createEllipseOrRectEditor();
            } else if (geometry instanceof Ellipse) {
                this.createEllipseOrRectEditor();
            } else if (geometry instanceof Sector);
            else if (geometry instanceof Polygon || geometry instanceof LineString) {
                this.createPolygonEditor();
            }
        };

        _proto.stop = function stop() {
            delete this._history;
            delete this._historyPointer;
            delete this._editOutline;

            this._switchGeometryEvents('off');

            var map = this.getMap();

            if (!map) {
                return;
            }

            delete this._shadow;

            this._geometry.config('draggable', this._geometryDraggble);

            delete this._geometryDraggble;

            this._geometry.show();

            this._editStageLayer.remove();

            this._shadowLayer.remove();

            this._clearAllListeners();

            this._refreshHooks = [];

            if (this.options['symbol']) {
                this._geometry.setSymbol(this._originalSymbol);

                delete this._originalSymbol;
            }

            this.editing = false;
        };

        _proto.isEditing = function isEditing() {
            if (isNil(this.editing)) {
                return false;
            }

            return this.editing;
        };

        _proto._getGeometryEvents = function _getGeometryEvents() {
            return {
                'symbolchange': this._onGeoSymbolChange,
                'positionchange shapechange': this._exeAndReset
            };
        };

        _proto._switchGeometryEvents = function _switchGeometryEvents(oper) {
            if (this._geometry) {
                var events = this._getGeometryEvents();

                for (var p in events) {
                    this._geometry[oper](p, events[p], this);
                }
            }
        };

        _proto._onGeoSymbolChange = function _onGeoSymbolChange(param) {
            if (this._shadow) {
                this._shadow.setSymbol(param.target._getInternalSymbol());
            }
        };

        _proto._onMarkerDragEnd = function _onMarkerDragEnd() {
            this._update('setCoordinates', this._shadow.getCoordinates().toArray());

            this._refresh();
        };

        _proto._createOrRefreshOutline = function _createOrRefreshOutline() {
            var geometry = this._geometry;
            var outline = this._editOutline;

            if (!outline) {
                outline = geometry.getOutline();

                this._editStageLayer.addGeometry(outline);

                this._editOutline = outline;

                this._addRefreshHook(this._createOrRefreshOutline);
            } else {
                outline.remove();
                this._editOutline = outline = geometry.getOutline();

                this._editStageLayer.addGeometry(outline);
            }

            return outline;
        };

        _proto._createCenterHandle = function _createCenterHandle() {
            var _this3 = this;

            var center = this._shadow.getCenter();

            var symbol = this.options['centerHandleSymbol'];
            var shadow;
            var handle = this.createHandle(center, {
                'symbol': symbol,
                'cursor': 'move',
                onDown: function onDown() {
                    shadow = _this3._shadow.copy();
                    var symbol = lowerSymbolOpacity(shadow._getInternalSymbol(), 0.5);
                    shadow.setSymbol(symbol).addTo(_this3._editStageLayer);
                },
                onMove: function onMove(v, param) {
                    var offset = param['coordOffset'];
                    shadow.translate(offset);
                },
                onUp: function onUp() {
                    _this3._update('setCoordinates', Coordinate.toNumberArrays(shadow.getCoordinates()));

                    shadow.remove();

                    _this3._refresh();
                }
            });

            this._addRefreshHook(function() {
                var center = _this3._shadow.getCenter();

                handle.setCoordinates(center);
            });
        };

        _proto._createHandleInstance = function _createHandleInstance(coordinate, opts) {
            var symbol = opts['symbol'];
            var handle = new Marker(coordinate, {
                'draggable': true,
                'dragShadow': false,
                'dragOnAxis': opts['axis'],
                'cursor': opts['cursor'],
                'symbol': symbol
            });
            return handle;
        };

        _proto.createHandle = function createHandle(coordinate, opts) {
            if (!opts) {
                opts = {};
            }

            var map = this.getMap();

            var handle = this._createHandleInstance(coordinate, opts);

            var me = this;

            function onHandleDragstart(param) {
                if (opts.onDown) {
                    this._geometry.fire('handledragstart');

                    opts.onDown.call(me, param['viewPoint'], param);
                }

                return false;
            }

            function onHandleDragging(param) {
                me._hideContext();

                var viewPoint = map._prjToViewPoint(handle._getPrjCoordinates());

                if (opts.onMove) {
                    this._geometry.fire('handledragging');

                    opts.onMove.call(me, viewPoint, param);
                }

                return false;
            }

            function onHandleDragEnd(ev) {
                if (opts.onUp) {
                    this._geometry.fire('handledragend');

                    opts.onUp.call(me, ev);
                }

                return false;
            }

            function onHandleRemove() {
                handle.config('draggable', false);
                handle.off('dragstart', onHandleDragstart, me);
                handle.off('dragging', onHandleDragging, me);
                handle.off('dragend', onHandleDragEnd, me);
                handle.off('removestart', onHandleRemove, me);
                delete handle['maptalks--editor-refresh-fn'];
            }

            handle.on('dragstart', onHandleDragstart, this);
            handle.on('dragging', onHandleDragging, this);
            handle.on('dragend', onHandleDragEnd, this);
            handle.on('removestart', onHandleRemove, this);

            if (opts.onRefresh) {
                handle['maptalks--editor-refresh-fn'] = opts.onRefresh;
            }

            this._editStageLayer.addGeometry(handle);

            return handle;
        };

        _proto._createResizeHandles = function _createResizeHandles(blackList, onHandleMove, onHandleUp) {
            var _this4 = this;

            var cursors = ['nw-resize', 'n-resize', 'ne-resize', 'w-resize', 'e-resize', 'sw-resize', 's-resize', 'se-resize'];
            var axis = [null, 'y', null, 'x', 'x', null, 'y', null];
            var geometry = this._geometry;

            function getResizeAnchors(ext) {
                return [new Point(ext['xmin'], ext['ymax']), new Point((ext['xmax'] + ext['xmin']) / 2, ext['ymax']), new Point(ext['xmax'], ext['ymax']), new Point(ext['xmin'], (ext['ymax'] + ext['ymin']) / 2), new Point(ext['xmax'], (ext['ymax'] + ext['ymin']) / 2), new Point(ext['xmin'], ext['ymin']), new Point((ext['xmax'] + ext['xmin']) / 2, ext['ymin']), new Point(ext['xmax'], ext['ymin'])];
            }

            if (!blackList) {
                blackList = [];
            }

            var me = this;
            var resizeHandles = [],
                anchorIndexes = {},
                map = this.getMap(),
                handleSymbol = this.options['vertexHandleSymbol'];

            var fnLocateHandles = function fnLocateHandles() {
                var pExt = geometry._getPainter().get2DExtent(),
                    anchors = getResizeAnchors(pExt);

                var _loop = function _loop(i) {
                    if (Array.isArray(blackList)) {
                        var isBlack = blackList.some(function(ele) {
                            return ele === i;
                        });

                        if (isBlack) {
                            return "continue";
                        }
                    }

                    var anchor = anchors[i],
                        coordinate = map.pointToCoordinate(anchor);

                    if (resizeHandles.length < anchors.length - blackList.length) {
                        var handle = _this4.createHandle(coordinate, {
                            'symbol': handleSymbol,
                            'cursor': cursors[i],
                            'axis': axis[i],
                            onMove: function(_index) {
                                return function(handleViewPoint) {
                                    me._updating = true;
                                    onHandleMove(handleViewPoint, _index);
                                    geometry.fire('resizing');
                                };
                            }(i),
                            onUp: function onUp() {
                                me._updating = false;
                                onHandleUp();

                                _this4._refresh();
                            }
                        });

                        handle.setId(i);
                        anchorIndexes[i] = resizeHandles.length;
                        resizeHandles.push(handle);
                    } else {
                        resizeHandles[anchorIndexes[i]].setCoordinates(coordinate);
                    }
                };

                for (var i = 0; i < anchors.length; i++) {
                    var _ret = _loop(i);

                    if (_ret === "continue") continue;
                }
            };

            fnLocateHandles();

            this._addRefreshHook(fnLocateHandles);

            return resizeHandles;
        };

        _proto.createMarkerEditor = function createMarkerEditor() {
            var _this5 = this;

            var geometryToEdit = this._geometry,
                shadow = this._shadow,
                map = this.getMap();

            if (!shadow._canEdit()) {
                if (console) {
                    console.warn('A marker can\'t be resized with symbol:', shadow.getSymbol());
                }

                return;
            }

            if (!this._history) {
                this._recordHistory(getUpdates());
            }

            var symbol = shadow._getInternalSymbol();

            var dxdy = new Point(0, 0);

            if (isNumber(symbol['markerDx'])) {
                dxdy.x = symbol['markerDx'];
            }

            if (isNumber(symbol['markerDy'])) {
                dxdy.y = symbol['markerDy'];
            }

            var blackList = null;

            if (VectorMarkerSymbolizer.test(symbol)) {
                if (symbol['markerType'] === 'pin' || symbol['markerType'] === 'pie' || symbol['markerType'] === 'bar') {
                    blackList = [5, 6, 7];
                }
            } else if (ImageMarkerSymbolizer.test(symbol) || VectorPathMarkerSymbolizer.test(symbol)) {
                blackList = [5, 6, 7];
            }

            var resizeAbilities = [2, 1, 2, 0, 0, 2, 1, 2];
            var aspectRatio;

            if (this.options['fixAspectRatio']) {
                var size = shadow.getSize();
                aspectRatio = size.width / size.height;
            }

            var resizeHandles = this._createResizeHandles(null, function(handleViewPoint, i) {
                if (blackList && blackList.indexOf(i) >= 0) {
                    var newCoordinates = map.viewPointToCoordinate(handleViewPoint.sub(dxdy));
                    var coordinates = shadow.getCoordinates();
                    newCoordinates.x = coordinates.x;
                    shadow.setCoordinates(newCoordinates);

                    _this5._updateCoordFromShadow(true);

                    var mirrorHandle = resizeHandles[resizeHandles.length - 1 - i];
                    var mirrorViewPoint = map.coordToViewPoint(mirrorHandle.getCoordinates());
                    handleViewPoint = mirrorViewPoint;
                }

                var viewCenter = map._pointToViewPoint(shadow._getCenter2DPoint()).add(dxdy),
                    symbol = shadow._getInternalSymbol();

                var wh = handleViewPoint.sub(viewCenter);

                if (blackList && handleViewPoint.y > viewCenter.y) {
                    wh.y = 0;
                }

                var r = blackList ? 1 : 2;
                var width = Math.abs(wh.x) * 2,
                    height = Math.abs(wh.y) * r;

                if (aspectRatio) {
                    width = Math.max(width, height * aspectRatio);
                    height = width / aspectRatio;
                }

                var ability = resizeAbilities[i];

                if (!(shadow instanceof TextBox)) {
                    if (aspectRatio || ability === 0 || ability === 2) {
                        symbol['markerWidth'] = width;
                    }

                    if (aspectRatio || ability === 1 || ability === 2) {
                        symbol['markerHeight'] = height;
                    }

                    shadow.setSymbol(symbol);
                    geometryToEdit.setSymbol(symbol);
                } else {
                    if (aspectRatio || ability === 0 || ability === 2) {
                        shadow.setWidth(width);
                        geometryToEdit.setWidth(width);
                    }

                    if (aspectRatio || ability === 1 || ability === 2) {
                        shadow.setHeight(height);
                        geometryToEdit.setHeight(height);
                    }
                }
            }, function() {
                _this5._update(getUpdates());
            });

            function getUpdates() {
                var updates = [
                    ['setCoordinates', shadow.getCoordinates().toArray()]
                ];

                if (shadow instanceof TextBox) {
                    updates.push(['setWidth', shadow.getWidth()]);
                    updates.push(['setHeight', shadow.getHeight()]);
                } else {
                    updates.push(['setSymbol', shadow.getSymbol()]);
                }

                return updates;
            }

            function onZoomEnd() {
                this._refresh();
            }

            this._addListener([map, 'zoomend', onZoomEnd]);
        };

        _proto.createCircleEditor = function createCircleEditor() {
            var _this6 = this;

            var circle = this._geometry,
                shadow = this._shadow;
            var map = this.getMap();

            if (!this._history) {
                this._recordHistory([
                    ['setCoordinates', shadow.getCoordinates().toArray()],
                    ['setRadius', shadow.getRadius()]
                ]);
            }

            this._createResizeHandles(null, function(handleViewPoint) {
                var center = circle.getCenter();
                var mouseCoordinate = map.viewPointToCoordinate(handleViewPoint);
                var wline = new LineString([
                    [center.x, center.y],
                    [mouseCoordinate.x, center.y]
                ]);
                var hline = new LineString([
                    [center.x, center.y],
                    [center.x, mouseCoordinate.y]
                ]);
                var r = Math.max(map.computeGeometryLength(wline), map.computeGeometryLength(hline));
                shadow.setRadius(r);
                circle.setRadius(r);
            }, function() {
                _this6._update('setRadius', shadow.getRadius());
            });
        };

        _proto.createEllipseOrRectEditor = function createEllipseOrRectEditor() {
            var _this7 = this;

            var resizeAbilities = [2, 1, 2, 0, 0, 2, 1, 2];
            var geometryToEdit = this._geometry,
                shadow = this._shadow;

            if (!this._history) {
                this._recordHistory(getUpdates());
            }

            var map = this.getMap();
            var isRect = this._geometry instanceof Rectangle;
            var aspectRatio;

            if (this.options['fixAspectRatio']) {
                aspectRatio = geometryToEdit.getWidth() / geometryToEdit.getHeight();
            }

            var resizeHandles = this._createResizeHandles(null, function(mouseViewPoint, i) {
                var r = isRect ? 1 : 2;
                var pointSub, w, h;
                var targetPoint = mouseViewPoint;
                var ability = resizeAbilities[i];

                if (isRect) {
                    var mirror = resizeHandles[7 - i];
                    var mirrorViewPoint = map.coordToViewPoint(mirror.getCoordinates());
                    pointSub = targetPoint.sub(mirrorViewPoint);
                    var absSub = pointSub.abs();
                    w = map.pixelToDistance(absSub.x, 0);
                    h = map.pixelToDistance(0, absSub.y);
                    var size = geometryToEdit.getSize();
                    var firstMirrorCoordinate = resizeHandles[0].getCoordinates();
                    var mouseCoordinate = map.viewPointToCoordinate(mouseViewPoint);
                    var mirrorCoordinate = mirror.getCoordinates();
                    var wline = new LineString([
                        [mirrorCoordinate.x, mirrorCoordinate.y],
                        [mouseCoordinate.x, mirrorCoordinate.y]
                    ]);
                    var hline = new LineString([
                        [mirrorCoordinate.x, mirrorCoordinate.y],
                        [mirrorCoordinate.x, mouseCoordinate.y]
                    ]);
                    w = map.computeGeometryLength(wline);
                    h = map.computeGeometryLength(hline);

                    if (ability === 0) {
                        if (aspectRatio) {
                            absSub.y = absSub.x / aspectRatio;
                            size.height = Math.abs(absSub.y);
                            h = w / aspectRatio;
                        }

                        targetPoint.y = mirrorViewPoint.y - size.height / 2;
                        mouseCoordinate.y = firstMirrorCoordinate.y;

                        if (i === 4) {
                            mouseCoordinate.x = Math.min(mouseCoordinate.x, firstMirrorCoordinate.x);
                        } else {
                            mouseCoordinate.x = Math.min(mouseCoordinate.x, mirrorCoordinate.x);
                        }
                    } else if (ability === 1) {
                        if (aspectRatio) {
                            absSub.x = absSub.y * aspectRatio;
                            size.width = Math.abs(absSub.x);
                            w = h * aspectRatio;
                        }

                        targetPoint.x = mirrorViewPoint.x - size.width / 2;
                        mouseCoordinate.x = firstMirrorCoordinate.x;
                        mouseCoordinate.y = Math.max(mouseCoordinate.y, mirrorCoordinate.y);
                    } else {
                        if (aspectRatio) {
                            if (w > h * aspectRatio) {
                                h = w / aspectRatio;
                                targetPoint.y = mirrorViewPoint.y + absSub.x * sign(pointSub.y) / aspectRatio;
                            } else {
                                w = h * aspectRatio;
                                targetPoint.x = mirrorViewPoint.x + absSub.y * sign(pointSub.x) * aspectRatio;
                            }
                        }

                        mouseCoordinate.x = Math.min(mouseCoordinate.x, mirrorCoordinate.x);
                        mouseCoordinate.y = Math.max(mouseCoordinate.y, mirrorCoordinate.y);
                    }

                    shadow.setCoordinates(mouseCoordinate);

                    _this7._updateCoordFromShadow(true);
                } else {
                    var center = geometryToEdit.getCenter();

                    var _mouseCoordinate = map.viewPointToCoordinate(targetPoint);

                    var _wline = new LineString([
                        [center.x, center.y],
                        [_mouseCoordinate.x, center.y]
                    ]);

                    var _hline = new LineString([
                        [center.x, center.y],
                        [center.x, _mouseCoordinate.y]
                    ]);

                    w = map.computeGeometryLength(_wline);
                    h = map.computeGeometryLength(_hline);

                    if (aspectRatio) {
                        w = Math.max(w, h * aspectRatio);
                        h = w / aspectRatio;
                    }
                }

                if (aspectRatio || ability === 0 || ability === 2) {
                    shadow.setWidth(w * r);
                    geometryToEdit.setWidth(w * r);
                }

                if (aspectRatio || ability === 1 || ability === 2) {
                    shadow.setHeight(h * r);
                    geometryToEdit.setHeight(h * r);
                }
            }, function() {
                _this7._update(getUpdates());
            });

            function getUpdates() {
                return [
                    ['setCoordinates', shadow.getCoordinates().toArray()],
                    ['setWidth', shadow.getWidth()],
                    ['setHeight', shadow.getHeight()]
                ];
            }
        };

        _proto.createPolygonEditor = function createPolygonEditor() {
            var map = this.getMap(),
                shadow = this._shadow,
                me = this,
                projection = map.getProjection();

            if (!this._history) {
                this._recordHistory('setCoordinates', Coordinate.toNumberArrays(shadow.getCoordinates()));
            }

            var verticeLimit = shadow instanceof Polygon ? 3 : 2;
            var propertyOfVertexRefreshFn = 'maptalks--editor-refresh-fn',
                propertyOfVertexIndex = 'maptalks--editor-vertex-index';
            var vertexHandles = {
                    0: []
                },
                newVertexHandles = {
                    0: []
                };

            function getVertexCoordinates(ringIndex) {
                if (ringIndex === void 0) {
                    ringIndex = 0;
                }

                if (shadow instanceof Polygon) {
                    var coordinates = shadow.getCoordinates()[ringIndex] || [];
                    return coordinates.slice(0, coordinates.length - 1);
                } else {
                    return shadow.getCoordinates();
                }
            }

            function getVertexPrjCoordinates(ringIndex) {
                if (ringIndex === void 0) {
                    ringIndex = 0;
                }

                if (ringIndex === 0) {
                    return shadow._getPrjCoordinates();
                }

                return shadow._getPrjHoles()[ringIndex - 1];
            }

            function onVertexAddOrRemove() {
                for (var ringIndex in vertexHandles) {
                    for (var i = vertexHandles[ringIndex].length - 1; i >= 0; i--) {
                        vertexHandles[ringIndex][i][propertyOfVertexIndex] = i;
                    }

                    for (var _i = newVertexHandles[ringIndex].length - 1; _i >= 0; _i--) {
                        newVertexHandles[ringIndex][_i][propertyOfVertexIndex] = _i;
                    }
                }

                me._updateCoordFromShadow();
            }

            function removeVertex(param) {
                var handle = param['target'],
                    index = handle[propertyOfVertexIndex];
                var ringIndex = isNumber(handle._ringIndex) ? handle._ringIndex : 0;
                var prjCoordinates = getVertexPrjCoordinates(ringIndex);

                if (prjCoordinates.length <= verticeLimit) {
                    return;
                }

                prjCoordinates.splice(index, 1);

                if (ringIndex > 0) {
                    shadow._prjHoles[ringIndex - 1] = prjCoordinates;
                } else {
                    shadow._setPrjCoordinates(prjCoordinates);
                }

                shadow._updateCache();

                vertexHandles[ringIndex].splice(index, 1)[0].remove();

                if (index < newVertexHandles[ringIndex].length) {
                    newVertexHandles[ringIndex].splice(index, 1)[0].remove();
                }

                var nextIndex;

                if (index === 0) {
                    nextIndex = newVertexHandles[ringIndex].length - 1;
                } else {
                    nextIndex = index - 1;
                }

                newVertexHandles[ringIndex].splice(nextIndex, 1)[0].remove();
                newVertexHandles[ringIndex].splice(nextIndex, 0, createNewVertexHandle.call(me, nextIndex, ringIndex));
                onVertexAddOrRemove();

                me._refresh();
            }

            function moveVertexHandle(handleViewPoint, index, ringIndex) {
                if (ringIndex === void 0) {
                    ringIndex = 0;
                }

                var vertice = getVertexPrjCoordinates(ringIndex);

                var nVertex = map._viewPointToPrj(handleViewPoint);

                var pVertex = vertice[index];
                pVertex.x = nVertex.x;
                pVertex.y = nVertex.y;

                shadow._updateCache();

                shadow.onShapeChanged();

                me._updateCoordFromShadow(true);

                var nextIndex;

                if (index === 0) {
                    nextIndex = newVertexHandles[ringIndex].length - 1;
                } else {
                    nextIndex = index - 1;
                }

                if (newVertexHandles[ringIndex][index]) {
                    newVertexHandles[ringIndex][index][propertyOfVertexRefreshFn]();
                }

                if (newVertexHandles[ringIndex][nextIndex]) {
                    newVertexHandles[ringIndex][nextIndex][propertyOfVertexRefreshFn]();
                }
            }

            function createVertexHandle(index, ringIndex) {
                if (ringIndex === void 0) {
                    ringIndex = 0;
                }

                var vertex = getVertexCoordinates(ringIndex)[index];
                var handle = me.createHandle(vertex, {
                    'symbol': me.options['vertexHandleSymbol'],
                    'cursor': 'pointer',
                    'axis': null,
                    onMove: function onMove(handleViewPoint) {
                        moveVertexHandle(handleViewPoint, handle[propertyOfVertexIndex], ringIndex);
                    },
                    onRefresh: function onRefresh() {
                        vertex = getVertexCoordinates(ringIndex)[handle[propertyOfVertexIndex]];
                        handle.setCoordinates(vertex);
                    },
                    onUp: function onUp() {
                        me._refresh();

                        me._updateCoordFromShadow();
                    },
                    onDown: function onDown(param, e) {
                        if (e && e.domEvent && e.domEvent.button === 2) {
                            return;
                        }
                    }
                });
                handle[propertyOfVertexIndex] = index;
                handle._ringIndex = ringIndex;
                handle.on(me.options['removeVertexOn'], removeVertex);
                return handle;
            }

            function createNewVertexHandle(index, ringIndex) {
                if (ringIndex === void 0) {
                    ringIndex = 0;
                }

                var vertexCoordinates = getVertexCoordinates(ringIndex);
                var nextVertex;

                if (index + 1 >= vertexCoordinates.length) {
                    nextVertex = vertexCoordinates[0];
                } else {
                    nextVertex = vertexCoordinates[index + 1];
                }

                var vertex = vertexCoordinates[index].add(nextVertex).multi(1 / 2);
                var handle = me.createHandle(vertex, {
                    'symbol': me.options['newVertexHandleSymbol'],
                    'cursor': 'pointer',
                    'axis': null,
                    onDown: function onDown(param, e) {
                        if (e && e.domEvent && e.domEvent.button === 2) {
                            return;
                        }

                        var prjCoordinates = getVertexPrjCoordinates(ringIndex);
                        var vertexIndex = handle[propertyOfVertexIndex];
                        var pVertex = projection.project(handle.getCoordinates());
                        prjCoordinates.splice(vertexIndex + 1, 0, pVertex);

                        if (ringIndex > 0) {
                            shadow._prjHoles[ringIndex - 1] = prjCoordinates;
                        } else {
                            shadow._setPrjCoordinates(prjCoordinates);
                        }

                        shadow._updateCache();

                        var symbol = handle.getSymbol();
                        delete symbol['opacity'];
                        handle.setSymbol(symbol);
                        newVertexHandles[ringIndex].splice(vertexIndex, 0, createNewVertexHandle.call(me, vertexIndex, ringIndex), createNewVertexHandle.call(me, vertexIndex + 1, ringIndex));
                    },
                    onMove: function onMove(handleViewPoint) {
                        moveVertexHandle(handleViewPoint, handle[propertyOfVertexIndex] + 1, ringIndex);
                    },
                    onUp: function onUp(e) {
                        if (e && e.domEvent && e.domEvent.button === 2) {
                            return;
                        }

                        var vertexIndex = handle[propertyOfVertexIndex];
                        removeFromArray(handle, newVertexHandles[ringIndex]);
                        handle.remove();
                        vertexHandles[ringIndex].splice(vertexIndex + 1, 0, createVertexHandle.call(me, vertexIndex + 1, ringIndex));
                        onVertexAddOrRemove();

                        me._updateCoordFromShadow();

                        me._refresh();
                    },
                    onRefresh: function onRefresh() {
                        vertexCoordinates = getVertexCoordinates(ringIndex);
                        var vertexIndex = handle[propertyOfVertexIndex];
                        var nextIndex;

                        if (vertexIndex === vertexCoordinates.length - 1) {
                            nextIndex = 0;
                        } else {
                            nextIndex = vertexIndex + 1;
                        }

                        var refreshVertex = vertexCoordinates[vertexIndex].add(vertexCoordinates[nextIndex]).multi(1 / 2);
                        handle.setCoordinates(refreshVertex);
                    }
                });
                handle[propertyOfVertexIndex] = index;
                return handle;
            }

            if (shadow instanceof Polygon) {
                var rings = shadow.getHoles().length + 1;

                for (var ringIndex = 0; ringIndex < rings; ringIndex++) {
                    vertexHandles[ringIndex] = [];
                    newVertexHandles[ringIndex] = [];
                    var vertexCoordinates = getVertexCoordinates(ringIndex);

                    for (var i = 0, len = vertexCoordinates.length; i < len; i++) {
                        vertexHandles[ringIndex].push(createVertexHandle.call(this, i, ringIndex));

                        if (i < len - 1) {
                            newVertexHandles[ringIndex].push(createNewVertexHandle.call(this, i, ringIndex));
                        }
                    }

                    newVertexHandles[ringIndex].push(createNewVertexHandle.call(this, vertexCoordinates.length - 1, ringIndex));
                }
            } else {
                var _ringIndex = 0;

                var _vertexCoordinates = getVertexCoordinates(_ringIndex);

                for (var _i2 = 0, _len = _vertexCoordinates.length; _i2 < _len; _i2++) {
                    vertexHandles[_ringIndex].push(createVertexHandle.call(this, _i2, _ringIndex));

                    if (_i2 < _len - 1) {
                        newVertexHandles[_ringIndex].push(createNewVertexHandle.call(this, _i2, _ringIndex));
                    }
                }
            }

            this._addRefreshHook(function() {
                for (var _ringIndex2 in newVertexHandles) {
                    for (var _i3 = newVertexHandles[_ringIndex2].length - 1; _i3 >= 0; _i3--) {
                        newVertexHandles[_ringIndex2][_i3][propertyOfVertexRefreshFn](_ringIndex2);
                    }
                }

                for (var _ringIndex3 in vertexHandles) {
                    for (var _i4 = vertexHandles[_ringIndex3].length - 1; _i4 >= 0; _i4--) {
                        vertexHandles[_ringIndex3][_i4][propertyOfVertexRefreshFn](_ringIndex3);
                    }
                }
            });
        };

        _proto._refresh = function _refresh() {
            if (this._refreshHooks) {
                for (var i = this._refreshHooks.length - 1; i >= 0; i--) {
                    this._refreshHooks[i].call(this);
                }
            }
        };

        _proto._hideContext = function _hideContext() {
            if (this._geometry) {
                this._geometry.closeMenu();

                this._geometry.closeInfoWindow();
            }
        };

        _proto._addListener = function _addListener(listener) {
            if (!this._eventListeners) {
                this._eventListeners = [];
            }

            this._eventListeners.push(listener);

            listener[0].on(listener[1], listener[2], this);
        };

        _proto._clearAllListeners = function _clearAllListeners() {
            if (this._eventListeners && this._eventListeners.length > 0) {
                for (var i = this._eventListeners.length - 1; i >= 0; i--) {
                    var listener = this._eventListeners[i];
                    listener[0].off(listener[1], listener[2], this);
                }

                this._eventListeners = [];
            }
        };

        _proto._addRefreshHook = function _addRefreshHook(fn) {
            if (!fn) {
                return;
            }

            if (!this._refreshHooks) {
                this._refreshHooks = [];
            }

            this._refreshHooks.push(fn);
        };

        _proto._update = function _update(method) {
            for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key = 1; _key < _len2; _key++) {
                args[_key - 1] = arguments[_key];
            }

            this._exeHistory([method, args]);

            this._recordHistory.apply(this, [method].concat(args));
        };

        _proto._updateCoordFromShadow = function _updateCoordFromShadow(ignoreRecord) {
            if (!this._shadow) {
                return;
            }

            var coords = this._shadow.getCoordinates();

            var geo = this._geometry;
            var updating = this._updating;
            this._updating = true;
            geo.setCoordinates(coords);

            if (!ignoreRecord) {
                this._recordHistory('setCoordinates', Coordinate.toNumberArrays(geo.getCoordinates()));
            }

            this._updating = updating;
        };

        _proto._recordHistory = function _recordHistory(method) {
            if (!this._history) {
                this._history = [];
                this._historyPointer = 0;
            }

            for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key2 = 1; _key2 < _len3; _key2++) {
                args[_key2 - 1] = arguments[_key2];
            }

            if (this._history.length) {
                var lastOperation = this._history[this._history.length - 1];

                if (lastOperation[0] === method && JSON.stringify(lastOperation[1]) === JSON.stringify(args)) {
                    return;
                }
            }

            if (this._historyPointer < this._history.length - 1) {
                this._history.splice(this._historyPointer + 1);
            }

            this._history.push([method, args]);

            this._historyPointer = this._history.length - 1;

            this._geometry.fire('editrecord');
        };

        _proto.cancel = function cancel() {
            if (!this._history || this._historyPointer === 0) {
                return this;
            }

            this._historyPointer = 0;
            var record = this._history[0];

            this._exeAndReset(record);

            return this;
        };

        _proto.undo = function undo() {
            if (!this._history || this._historyPointer === 0) {
                return this;
            }

            var record = this._history[--this._historyPointer];

            this._exeAndReset(record);

            return this;
        };

        _proto.redo = function redo() {
            if (!this._history || this._historyPointer === this._history.length - 1) {
                return this;
            }

            var record = this._history[++this._historyPointer];

            this._exeAndReset(record);

            return this;
        };

        _proto._exeAndReset = function _exeAndReset(record) {
            if (this._updating) {
                return;
            }

            this._exeHistory(record);

            var history = this._history,
                pointer = this._historyPointer;
            this.stop();
            this._history = history;
            this._historyPointer = pointer;
            this.start();
        };

        _proto._exeHistory = function _exeHistory(record) {
            var _this8 = this;

            if (!Array.isArray(record)) {
                return;
            }

            var updating = this._updating;
            this._updating = true;
            var geo = this._geometry;

            if (Array.isArray(record[0])) {
                record[0].forEach(function(o) {
                    var m = o[0],
                        args = o.slice(1);

                    _this8._shadow[m].apply(_this8._shadow, args);

                    geo[m].apply(geo, args);
                });
            } else {
                this._shadow[record[0]].apply(this._shadow, record[1]);

                geo[record[0]].apply(geo, record[1]);
            }

            this._updating = updating;
        };

        return GeometryEditor;
    }(Eventable(Class));

    GeometryEditor.mergeOptions(options$z);

    var TextEditable = {
        startEditText: function startEditText() {
            if (!this.getMap()) {
                return this;
            }

            this.hide();
            this.endEditText();

            this._prepareEditor();

            this._fireEvent('edittextstart');

            return this;
        },
        endEditText: function endEditText() {
            if (this._textEditor) {
                var html = this._textEditor.innerHTML;
                html = html.replace(/<p>/ig, '').replace(/<\/p>/ig, '<br/>');
                this._textEditor.innerHTML = html;

                var content = this._textEditor.innerText.replace(/[\r\n]+$/gi, '');

                this.setContent(content);
                off(this._textEditor, 'mousedown dblclick', stopPropagation);
                this.getMap().off('mousedown', this.endEditText, this);

                this._editUIMarker.remove();

                delete this._editUIMarker;
                this._textEditor.onkeyup = null;
                delete this._textEditor;
                this.show();

                this._fireEvent('edittextend');
            }

            return this;
        },
        isEditingText: function isEditingText() {
            if (this._textEditor) {
                return true;
            }

            return false;
        },
        getTextEditor: function getTextEditor() {
            return this._editUIMarker;
        },
        _prepareEditor: function _prepareEditor() {
            var map = this.getMap();

            var editContainer = this._createEditor();

            this._textEditor = editContainer;
            map.on('mousedown', this.endEditText, this);

            var offset = this._getEditorOffset();

            this._editUIMarker = new UIMarker(this.getCoordinates(), {
                'animation': null,
                'content': editContainer,
                'dx': offset.dx,
                'dy': offset.dy
            }).addTo(map);

            this._setCursorToLast(this._textEditor);
        },
        _getEditorOffset: function _getEditorOffset() {
            var symbol = this._getInternalSymbol() || {};
            var dx = 0,
                dy = 0;
            var textAlign = symbol['textHorizontalAlignment'];

            if (textAlign === 'middle' || isNil(textAlign)) {
                dx = (symbol['textDx'] || 0) - 2;
                dy = (symbol['textDy'] || 0) - 2;
            } else {
                dx = (symbol['markerDx'] || 0) - 2;
                dy = (symbol['markerDy'] || 0) - 2;
            }

            return {
                'dx': dx,
                'dy': dy
            };
        },
        _createEditor: function _createEditor() {
            var content = this.getContent();
            var labelSize = this.getSize(),
                symbol = this._getInternalSymbol() || {},
                width = labelSize.width,
                textColor = symbol['textFill'] || '#000000',
                textSize = symbol['textSize'] || 12,
                height = labelSize.height,
                lineColor = symbol['markerLineColor'] || '#000',
                fill = symbol['markerFill'] || '#3398CC',
                spacing = symbol['textLineSpacing'] || 0;
            var editor = createEl('div');
            editor.contentEditable = true;
            editor.style.cssText = "background:" + fill + "; border:1px solid " + lineColor + ";\n            color:" + textColor + ";font-size:" + textSize + "px;width:" + (width - 2) + "px;height:" + (height - 2) + "px;margin: auto;\n            line-height:" + (textSize + spacing) + "px;outline: 0; padding:0; margin:0;word-wrap: break-word;\n            overflow: hidden;-webkit-user-modify: read-write-plaintext-only;";
            editor.innerText = content;
            on(editor, 'mousedown dblclick', stopPropagation);

            editor.onkeyup = function(event) {
                var h = editor.style.height || 0;

                if (event.keyCode === 13) {
                    editor.style.height = parseInt(h) + textSize / 2 + 'px';
                }
            };

            return editor;
        },
        _setCursorToLast: function _setCursorToLast(obj) {
            var range;

            if (window.getSelection) {
                obj.focus();
                range = window.getSelection();
                range.selectAllChildren(obj);
                range.collapseToEnd();
            } else if (document.selection) {
                range = document.selection.createRange();
                range.moveToElementText(obj);
                range.collapse(false);
                range.select();
            }
        }
    };
    TextMarker.include(TextEditable);

    Geometry.include({
        animate: function animate(styles, options, step) {
            var _this = this;

            if (this._animPlayer) {
                this._animPlayer.finish();
            }

            if (isFunction(options)) {
                step = options;
            }

            if (!options) {
                options = {};
            }

            var map = this.getMap(),
                projection = this._getProjection(),
                symbol = this.getSymbol() || {},
                stylesToAnimate = this._prepareAnimationStyles(styles);

            var preTranslate;
            var isFocusing = options['focus'];
            delete this._animationStarted;

            if (map) {
                var renderer = map._getRenderer();

                var framer = function framer(fn) {
                    renderer.callInNextFrame(fn);
                };

                options['framer'] = framer;
            }

            var player = Animation.animate(stylesToAnimate, options, function(frame) {
                if (map && map.isRemoved()) {
                    player.finish();
                    return;
                }

                if (map && !_this._animationStarted && isFocusing) {
                    map.onMoveStart();
                }

                var styles = frame.styles;

                for (var p in styles) {
                    if (p !== 'symbol' && p !== 'translate' && styles.hasOwnProperty(p)) {
                        var fnName = 'set' + p[0].toUpperCase() + p.slice(1);

                        _this[fnName](styles[p]);
                    }
                }

                var translate = styles['translate'];

                if (translate) {
                    var toTranslate = translate;

                    if (preTranslate) {
                        toTranslate = translate.sub(preTranslate);
                    }

                    preTranslate = translate;

                    _this.translate(toTranslate);
                }

                var dSymbol = styles['symbol'];

                if (dSymbol) {
                    _this.setSymbol(extendSymbol(symbol, dSymbol));
                }

                if (map && isFocusing) {
                    var pcenter = projection.project(_this.getCenter());

                    map._setPrjCenter(pcenter);

                    var e = map._parseEventFromCoord(projection.unproject(pcenter));

                    if (player.playState !== 'running') {
                        map.onMoveEnd(e);
                    } else {
                        map.onMoving(e);
                    }
                }

                _this._fireAnimateEvent(player.playState);

                if (step) {
                    step(frame);
                }
            }, this);
            this._animPlayer = player;
            return this._animPlayer.play();
        },
        _prepareAnimationStyles: function _prepareAnimationStyles(styles) {
            var symbol = this._getInternalSymbol();

            var stylesToAnimate = {};

            for (var p in styles) {
                if (styles.hasOwnProperty(p)) {
                    var v = styles[p];

                    if (p !== 'translate' && p !== 'symbol') {
                        var fnName = 'get' + p[0].toUpperCase() + p.substring(1);
                        var current = this[fnName]();
                        stylesToAnimate[p] = [current, v];
                    } else if (p === 'symbol') {
                        var symbolToAnimate = void 0;

                        if (Array.isArray(styles['symbol'])) {
                            if (!Array.isArray(symbol)) {
                                throw new Error('geometry\'symbol isn\'t a composite symbol, while the symbol in styles is.');
                            }

                            symbolToAnimate = [];
                            var symbolInStyles = styles['symbol'];

                            for (var i = 0; i < symbolInStyles.length; i++) {
                                if (!symbolInStyles[i]) {
                                    symbolToAnimate.push(null);
                                    continue;
                                }

                                var a = {};

                                for (var sp in symbolInStyles[i]) {
                                    if (symbolInStyles[i].hasOwnProperty(sp)) {
                                        a[sp] = [symbol[i][sp], symbolInStyles[i][sp]];
                                    }
                                }

                                symbolToAnimate.push(a);
                            }
                        } else {
                            if (Array.isArray(symbol)) {
                                throw new Error('geometry\'symbol is a composite symbol, while the symbol in styles isn\'t.');
                            }

                            symbolToAnimate = {};

                            for (var _sp in v) {
                                if (v.hasOwnProperty(_sp)) {
                                    symbolToAnimate[_sp] = [symbol[_sp], v[_sp]];
                                }
                            }
                        }

                        stylesToAnimate['symbol'] = symbolToAnimate;
                    } else if (p === 'translate') {
                        stylesToAnimate['translate'] = new Coordinate(v);
                    }
                }
            }

            return stylesToAnimate;
        },
        _fireAnimateEvent: function _fireAnimateEvent(playState) {
            if (playState === 'finished') {
                delete this._animationStarted;

                this._fireEvent('animateend');
            } else if (playState === 'running') {
                if (this._animationStarted) {
                    this._fireEvent('animating');
                } else {
                    this._fireEvent('animatestart');

                    this._animationStarted = true;
                }
            }
        }
    });

    var DRAG_STAGE_LAYER_ID = INTERNAL_LAYER_PREFIX + '_drag_stage';
    var EVENTS$2 = Browser$1.touch ? 'touchstart mousedown' : 'mousedown';

    var GeometryDragHandler = function(_Handler) {
        _inheritsLoose(GeometryDragHandler, _Handler);

        function GeometryDragHandler(target) {
            return _Handler.call(this, target) || this;
        }

        var _proto = GeometryDragHandler.prototype;

        _proto.addHooks = function addHooks() {
            this.target.on(EVENTS$2, this._startDrag, this);
        };

        _proto.removeHooks = function removeHooks() {
            this._endDrag();

            this.target.off(EVENTS$2, this._startDrag, this);
            delete this.container;
        };

        _proto._prepareDragHandler = function _prepareDragHandler() {
            this._dragHandler = new DragHandler(this.container);

            this._dragHandler.on('dragging', this._dragging, this).on('mouseup', this._endDrag, this).enable();
        };

        _proto._prepareShadow = function _prepareShadow() {
            var _this = this;

            var target = this.target;

            this._prepareDragStageLayer();

            if (this._shadow) {
                this._shadow.remove();
            }

            var shadow = this._shadow = target.copy();

            if (shadow.getGeometries) {
                var shadows = shadow.getGeometries();
                var geos = target.getGeometries();
                shadows.forEach(function(g, i) {
                    _this._updateShadowSymbol(g, geos[i]);
                });
            } else {
                this._updateShadowSymbol(shadow, target);
            }

            shadow.setId(null);

            this._prepareShadowConnectors();
        };

        _proto._updateShadowSymbol = function _updateShadowSymbol(shadow, target) {
            shadow.setSymbol(target._getInternalSymbol());

            if (target.options['dragShadow']) {
                var symbol = lowerSymbolOpacity(shadow._getInternalSymbol(), 0.5);
                shadow.setSymbol(symbol);
            }
        };

        _proto._prepareShadowConnectors = function _prepareShadowConnectors() {
            var target = this.target;
            var shadow = this._shadow;

            var resources = this._dragStageLayer._getRenderer().resources;

            var shadowConnectors = [];

            if (ConnectorLine._hasConnectors(target)) {
                var connectors = ConnectorLine._getConnectors(target);

                for (var i = 0, l = connectors.length; i < l; i++) {
                    var targetConn = connectors[i];

                    var connOptions = targetConn.config(),
                        connSymbol = targetConn._getInternalSymbol();

                    connOptions['symbol'] = lowerSymbolOpacity(connSymbol, 0.5);
                    var conn = void 0;

                    if (targetConn.getConnectSource() === target) {
                        conn = new targetConn.constructor(shadow, targetConn.getConnectTarget(), connOptions);
                    } else {
                        conn = new targetConn.constructor(targetConn.getConnectSource(), shadow, connOptions);
                    }

                    shadowConnectors.push(conn);

                    if (targetConn.getLayer() && targetConn.getLayer()._getRenderer()) {
                        resources.merge(targetConn.getLayer()._getRenderer().resources);
                    }
                }
            }

            this._shadowConnectors = shadowConnectors;
            shadowConnectors.push(shadow);

            this._dragStageLayer.bringToFront().addGeometry(shadowConnectors);
        };

        _proto._onTargetUpdated = function _onTargetUpdated() {
            if (this._shadow) {
                this._shadow.setSymbol(this.target._getSymbol());
            }
        };

        _proto._prepareDragStageLayer = function _prepareDragStageLayer() {
            var map = this.target.getMap(),
                layer = this.target.getLayer();
            this._dragStageLayer = map.getLayer(DRAG_STAGE_LAYER_ID);

            if (!this._dragStageLayer) {
                this._dragStageLayer = new VectorLayer(DRAG_STAGE_LAYER_ID, {
                    enableAltitude: layer.options['enableAltitude'],
                    altitudeProperty: layer.options['altitudeProperty']
                });
                map.addLayer(this._dragStageLayer);
            }

            var resources = new ResourceCache();
            resources.merge(layer._getRenderer().resources);
            this._dragStageLayer._getRenderer().resources = resources;
        };

        _proto._startDrag = function _startDrag(param) {
            var map = this.target.getMap();

            if (!map) {
                return;
            }

            var parent = this.target._getParent();

            if (parent) {
                return;
            }

            if (this.isDragging()) {
                return;
            }

            var domEvent = param['domEvent'];

            if (domEvent.touches && domEvent.touches.length > 1 || domEvent.button === 2) {
                return;
            }

            this.container = map._panels.mapWrapper || map._containerDOM;
            this.target.on('click', this._endDrag, this);
            this._lastCoord = this._correctCoord(param['coordinate']);
            this._lastPoint = param['containerPoint'];

            this._prepareDragHandler();

            this._dragHandler.onMouseDown(param['domEvent']);

            on(this.container, 'mouseleave', this._endDrag, this);
            this._startParam = param;
            this._moved = false;
            return;
        };

        _proto._dragging = function _dragging(param) {
            var target = this.target;

            var map = target.getMap(),
                e = map._parseEvent(param['domEvent']);

            var domEvent = e['domEvent'];

            if (domEvent.touches && domEvent.touches.length > 1) {
                return;
            }

            if (!this._moved) {
                this._moved = true;
                target.on('symbolchange', this._onTargetUpdated, this);
                this._isDragging = true;

                this._prepareShadow();

                if (!target.options['dragShadow']) {
                    target.hide();
                }

                this._shadow._fireEvent('dragstart', e);

                this.target._fireEvent('dragstart', this._startParam || e);

                delete this._startParam;
                return;
            }

            if (!this._shadow) {
                return;
            }

            var axis = this._shadow.options['dragOnAxis'],
                coord = this._correctCoord(e['coordinate']),
                point = e['containerPoint'];

            this._lastPoint = this._lastPoint || point;
            this._lastCoord = this._lastCoord || coord;
            var pointOffset = point.sub(this._lastPoint);
            var coordOffset = coord.sub(this._lastCoord);

            if (axis === 'x') {
                pointOffset.y = coordOffset.y = 0;
            } else if (axis === 'y') {
                pointOffset.x = coordOffset.x = 0;
            }

            this._lastPoint = point;
            this._lastCoord = coord;

            this._shadow.translate(coordOffset);

            if (!target.options['dragShadow']) {
                target.translate(coordOffset);
            }

            e['coordOffset'] = coordOffset;
            e['pointOffset'] = pointOffset;

            this._shadow._fireEvent('dragging', e);

            target._fireEvent('dragging', e);
        };

        _proto._endDrag = function _endDrag(param) {
            if (this._dragHandler) {
                this._dragHandler.disable();

                delete this._dragHandler;
            }

            if (this.container) {
                off(this.container, 'mouseleave', this._endDrag, this);
            }

            if (!this.target) {
                return;
            }

            var target = this.target;
            target.off('click', this._endDrag, this);
            target.off('symbolchange', this._onTargetUpdated, this);
            delete this._lastCoord;
            delete this._lastPoint;
            this._isDragging = false;
            var map = target.getMap();

            if (this.enabled() && map) {
                var e = map._parseEvent(param ? param['domEvent'] : null);

                this._updateTargetAndRemoveShadow(e);

                if (this._moved) {
                    target._fireEvent('dragend', e);
                }
            }
        };

        _proto.isDragging = function isDragging() {
            if (!this._isDragging) {
                return false;
            }

            return true;
        };

        _proto._updateTargetAndRemoveShadow = function _updateTargetAndRemoveShadow(eventParam) {
            var target = this.target,
                map = target.getMap();

            if (!target.options['dragShadow']) {
                target.show();
            }

            var shadow = this._shadow;

            if (shadow) {
                if (target.options['dragShadow']) {
                    if (target.getGeometries) {
                        var shadows = shadow.getGeometries();
                        var geos = target.getGeometries();
                        shadows.forEach(function(g, i) {
                            geos[i].setCoordinates(shadows[i].getCoordinates());
                        });
                    } else {
                        target.setCoordinates(shadow.getCoordinates());
                    }
                }

                shadow._fireEvent('dragend', eventParam);

                shadow.remove();
                delete this._shadow;
            }

            if (this._shadowConnectors) {
                map.getLayer(DRAG_STAGE_LAYER_ID).removeGeometry(this._shadowConnectors);
                delete this._shadowConnectors;
            }

            if (this._dragStageLayer) {
                this._dragStageLayer.remove();
            }
        };

        _proto._correctCoord = function _correctCoord(coord) {
            var map = this.target.getMap();

            if (!map.getPitch()) {
                return coord;
            }

            var painter = this.target._getPainter();

            if (!painter.getMinAltitude()) {
                return coord;
            }

            var alt = (painter.getMinAltitude() + painter.getMaxAltitude()) / 2;
            return map.locateByPoint(coord, 0, -alt);
        };

        return GeometryDragHandler;
    }(Handler$1);

    Geometry.mergeOptions({
        'draggable': false,
        'dragShadow': true,
        'dragOnAxis': null
    });
    Geometry.addInitHook('addHandler', 'draggable', GeometryDragHandler);
    Geometry.include({
        isDragging: function isDragging() {
            if (this._getParent()) {
                return this._getParent().isDragging();
            }

            if (this['draggable']) {
                return this['draggable'].isDragging();
            }

            return false;
        }
    });

    Geometry.include({
        startEdit: function startEdit(opts) {
            if (!this.getMap() || !this.options['editable']) {
                return this;
            }

            this.endEdit();
            this._editor = new GeometryEditor(this, opts);

            this._editor.start();

            this.fire('editstart');
            return this;
        },
        endEdit: function endEdit() {
            if (this._editor) {
                this._editor.stop();

                delete this._editor;
                this.fire('editend');
            }

            return this;
        },
        redoEdit: function redoEdit() {
            if (!this.isEditing()) {
                return this;
            }

            this._editor.redo();

            this.fire('redoedit');
            return this;
        },
        undoEdit: function undoEdit() {
            if (!this.isEditing()) {
                return this;
            }

            this._editor.undo();

            this.fire('undoedit');
            return this;
        },
        cancelEdit: function cancelEdit() {
            if (!this.isEditing()) {
                return this;
            }

            this._editor.cancel();

            this.fire('canceledit');
            return this;
        },
        isEditing: function isEditing() {
            if (this._editor) {
                return this._editor.isEditing();
            }

            return false;
        }
    });

    Geometry.include({
        _onEvent: function _onEvent(event, type) {
            if (!this.getMap()) {
                return;
            }

            var eventType = type || this._getEventTypeToFire(event);

            if (eventType === 'contextmenu' && this.listens('contextmenu')) {
                stopPropagation(event);
                preventDefault(event);
            }

            var params = this._getEventParams(event);

            this._fireEvent(eventType, params);
        },
        _getEventTypeToFire: function _getEventTypeToFire(domEvent) {
            return domEvent.type;
        },
        _getEventParams: function _getEventParams(e) {
            var map = this.getMap();
            var eventParam = {
                'domEvent': e
            };
            var actual = e.touches && e.touches.length > 0 ? e.touches[0] : e.changedTouches && e.changedTouches.length > 0 ? e.changedTouches[0] : e;

            if (actual) {
                var containerPoint = getEventContainerPoint(actual, map._containerDOM);
                eventParam['coordinate'] = map.containerPointToCoordinate(containerPoint);
                eventParam['containerPoint'] = containerPoint;
                eventParam['viewPoint'] = map.containerPointToViewPoint(containerPoint);
                eventParam['pont2d'] = map._containerPointToPoint(containerPoint);
            }

            return eventParam;
        }
    });

    Geometry.include({
        setInfoWindow: function setInfoWindow(options) {
            this.removeInfoWindow();

            if (options instanceof InfoWindow) {
                this._infoWindow = options;
                this._infoWinOptions = extend({}, this._infoWindow.options);

                this._infoWindow.addTo(this);

                return this;
            }

            this._infoWinOptions = extend({}, options);

            if (this._infoWindow) {
                this._infoWindow.setOptions(options);
            } else if (this.getMap()) {
                this._bindInfoWindow(this._infoWinOptions);
            }

            return this;
        },
        getInfoWindow: function getInfoWindow() {
            if (!this._infoWindow) {
                return null;
            }

            return this._infoWindow;
        },
        openInfoWindow: function openInfoWindow(coordinate) {
            if (!this.getMap()) {
                return this;
            }

            if (!coordinate) {
                coordinate = this.getCenter();
            }

            if (!this._infoWindow) {
                if (this._infoWinOptions && this.getMap()) {
                    this._bindInfoWindow(this._infoWinOptions);

                    this._infoWindow.show(coordinate);
                }
            } else {
                this._infoWindow.show(coordinate);
            }

            return this;
        },
        closeInfoWindow: function closeInfoWindow() {
            if (this._infoWindow) {
                this._infoWindow.hide();
            }

            return this;
        },
        removeInfoWindow: function removeInfoWindow() {
            this._unbindInfoWindow();

            delete this._infoWinOptions;
            delete this._infoWindow;
            return this;
        },
        _bindInfoWindow: function _bindInfoWindow(options) {
            this._infoWindow = new InfoWindow(options);

            this._infoWindow.addTo(this);

            return this;
        },
        _unbindInfoWindow: function _unbindInfoWindow() {
            if (this._infoWindow) {
                this.closeInfoWindow();

                this._infoWindow.remove();

                delete this._infoWindow;
            }

            return this;
        }
    });

    var LRUCache = function() {
        function LRUCache(max, onRemove) {
            this.max = max;
            this.onRemove = onRemove;
            this.reset();
        }

        var _proto = LRUCache.prototype;

        _proto.reset = function reset() {
            for (var key in this.data) {
                this.onRemove(this.data[key]);
            }

            this.data = {};
            this.order = [];
            return this;
        };

        _proto.clear = function clear() {
            this.reset();
            delete this.onRemove;
        };

        _proto.add = function add(key, data) {
            if (this.has(key)) {
                this.order.splice(this.order.indexOf(key), 1);
                this.data[key] = data;
                this.order.push(key);
            } else {
                this.data[key] = data;
                this.order.push(key);

                if (this.order.length > this.max) {
                    var removedData = this.getAndRemove(this.order[0]);
                    if (removedData) this.onRemove(removedData);
                }
            }

            return this;
        };

        _proto.has = function has(key) {
            return key in this.data;
        };

        _proto.keys = function keys() {
            return this.order;
        };

        _proto.getAndRemove = function getAndRemove(key) {
            if (!this.has(key)) {
                return null;
            }

            var data = this.data[key];
            delete this.data[key];
            this.order.splice(this.order.indexOf(key), 1);
            return data;
        };

        _proto.get = function get(key) {
            if (!this.has(key)) {
                return null;
            }

            var data = this.data[key];
            return data;
        };

        _proto.remove = function remove(key) {
            if (!this.has(key)) {
                return this;
            }

            var data = this.data[key];
            delete this.data[key];
            this.onRemove(data);
            this.order.splice(this.order.indexOf(key), 1);
            return this;
        };

        _proto.setMaxSize = function setMaxSize(max) {
            this.max = max;

            while (this.order.length > this.max) {
                var removedData = this.getAndRemove(this.order[0]);
                if (removedData) this.onRemove(removedData);
            }

            return this;
        };

        return LRUCache;
    }();

    var TILE_POINT = new Point(0, 0);
    var TEMP_POINT$3 = new Point(0, 0);
    var TEMP_POINT1$2 = new Point(0, 0);
    var TEMP_POINT2$1 = new Point(0, 0);

    var TileLayerCanvasRenderer = function(_CanvasRenderer) {
        _inheritsLoose(TileLayerCanvasRenderer, _CanvasRenderer);

        function TileLayerCanvasRenderer(layer) {
            var _this;

            _this = _CanvasRenderer.call(this, layer) || this;
            _this.tilesInView = {};
            _this.tilesLoading = {};
            _this._parentTiles = [];
            _this._childTiles = [];
            _this.tileCache = new LRUCache(layer.options['maxCacheSize'], _this.deleteTile.bind(_assertThisInitialized(_assertThisInitialized(_this))));
            return _this;
        }

        var _proto = TileLayerCanvasRenderer.prototype;

        _proto.getCurrentTileZoom = function getCurrentTileZoom() {
            return this._tileZoom;
        };

        _proto.draw = function draw() {
            var map = this.getMap();

            if (!this.isDrawable()) {
                return;
            }

            var mask2DExtent = this.prepareCanvas();

            if (mask2DExtent) {
                if (!mask2DExtent.intersects(this.canvasExtent2D)) {
                    this.completeRender();
                    return;
                }
            }

            var layer = this.layer;
            var tileGrids = layer.getTiles().tileGrids;

            if (!tileGrids || !tileGrids.length) {
                this.completeRender();
                return;
            }

            var loadingCount = 0;
            var loading = false;
            var checkedTiles = {};
            var tiles = [],
                parentTiles = [],
                parentKeys = {},
                childTiles = [],
                childKeys = {},
                placeholders = [],
                placeholderKeys = {};
            var tileQueue = {};

            var preLoadingCount = this._markTiles(),
                loadingLimit = this._getLoadLimit();

            var l = tileGrids.length;
            this._tileZoom = tileGrids[0]['zoom'];

            for (var i = 0; i < l; i++) {
                var tileGrid = tileGrids[i];
                var allTiles = tileGrid['tiles'];

                var placeholder = this._generatePlaceHolder(tileGrid.zoom);

                for (var _i = 0, _l = allTiles.length; _i < _l; _i++) {
                    var tile = allTiles[_i],
                        tileId = tile['id'];
                    var tileLoading = false;

                    if (this._isLoadingTile(tileId)) {
                        tileLoading = loading = true;
                        this.tilesLoading[tileId].current = true;
                    } else {
                        var cached = this._getCachedTile(tileId);

                        if (cached) {
                            if (cached.image && this.getTileOpacity(cached.image) < 1) {
                                tileLoading = loading = true;
                            }

                            tiles.push(cached);
                        } else {
                            tileLoading = loading = true;
                            var hitLimit = loadingLimit && loadingCount + preLoadingCount[0] > loadingLimit;

                            if (!hitLimit && (!map.isInteracting() || map.isMoving() || map.isRotating())) {
                                loadingCount++;
                                var key = tileId;
                                tileQueue[key] = tile;
                            }
                        }
                    }

                    if (!tileLoading) continue;

                    if (checkedTiles[tileId]) {
                        continue;
                    }

                    checkedTiles[tileId] = 1;

                    if (placeholder && !placeholderKeys[tileId]) {
                        tile.cache = false;
                        placeholders.push({
                            image: placeholder,
                            info: tile
                        });
                        placeholderKeys[tileId] = 1;
                    }

                    var parentTile = this._findParentTile(tile);

                    if (parentTile) {
                        var parentId = parentTile.info.id;

                        if (parentKeys[parentId] === undefined) {
                            parentKeys[parentId] = parentTiles.length;
                            parentTiles.push(parentTile);
                        }
                    } else if (!parentTiles.length) {
                        var children = this._findChildTiles(tile);

                        if (children.length) {
                            children.forEach(function(c) {
                                if (!childKeys[c.info.id]) {
                                    childTiles.push(c);
                                    childKeys[c.info.id] = 1;
                                }
                            });
                        }
                    }
                }
            }

            if (parentTiles.length) {
                childTiles.length = 0;
                this._childTiles.length = 0;
            }

            this._drawTiles(tiles, parentTiles, childTiles, placeholders);

            if (!loadingCount) {
                if (!loading) {
                    if (!map.isAnimating() && (this._parentTiles.length || this._childTiles.length)) {
                        this._parentTiles = [];
                        this._childTiles = [];
                        this.setToRedraw();
                    }

                    this.completeRender();
                }
            } else {
                this.loadTileQueue(tileQueue);
            }

            this._retireTiles();
        };

        _proto.isTileCachedOrLoading = function isTileCachedOrLoading(tileId) {
            return this.tilesLoading[tileId] || this.tilesInView[tileId] || this.tileCache.get(tileId);
        };

        _proto._drawTiles = function _drawTiles(tiles, parentTiles, childTiles, placeholders) {
            var _this2 = this;

            if (parentTiles.length) {
                parentTiles.sort(function(t1, t2) {
                    return Math.abs(t2.info.z - _this2._tileZoom) - Math.abs(t1.info.z - _this2._tileZoom);
                });
                this._parentTiles = parentTiles;
            }

            if (childTiles.length) {
                this._childTiles = childTiles;
            }

            var context = {
                tiles: tiles,
                parentTiles: this._parentTiles,
                childTiles: this._childTiles
            };
            this.onDrawTileStart(context);

            this._parentTiles.forEach(function(t) {
                return _this2._drawTileAndCache(t);
            });

            this._childTiles.forEach(function(t) {
                return _this2._drawTile(t.info, t.image);
            });

            placeholders.forEach(function(t) {
                return _this2._drawTile(t.info, t.image);
            });
            var layer = this.layer,
                map = this.getMap();

            if (!layer.options['cascadeTiles'] || map.getPitch() <= map.options['cascadePitches'][0]) {
                tiles.forEach(function(t) {
                    return _this2._drawTileAndCache(t);
                });
            } else {
                this.writeZoomStencil();
                var started = false;

                for (var i = 0, l = tiles.length; i < l; i++) {
                    if (tiles[i].info.z !== this._tileZoom) {
                        if (!started) {
                            this.startZoomStencilTest();
                            started = true;
                        } else {
                            this.resumeZoomStencilTest();
                        }
                    } else if (started) {
                        this.pauseZoomStencilTest();
                    }

                    this._drawTileAndCache(tiles[i]);
                }

                this.endZoomStencilTest();
            }

            this.onDrawTileEnd(context);
        };

        _proto.writeZoomStencil = function writeZoomStencil() {};

        _proto.startZoomStencilTest = function startZoomStencilTest() {};

        _proto.endZoomStencilTest = function endZoomStencilTest() {};

        _proto.pauseZoomStencilTest = function pauseZoomStencilTest() {};

        _proto.resumeZoomStencilTest = function resumeZoomStencilTest() {};

        _proto.onDrawTileStart = function onDrawTileStart() {};

        _proto.onDrawTileEnd = function onDrawTileEnd() {};

        _proto._drawTile = function _drawTile(info, image) {
            if (image) {
                this.drawTile(info, image);
            }
        };

        _proto._drawTileAndCache = function _drawTileAndCache(tile) {
            tile.current = true;
            this.tilesInView[tile.info.id] = tile;

            this._drawTile(tile.info, tile.image);

            this.tileCache.add(tile.info.id, tile);
        };

        _proto.drawOnInteracting = function drawOnInteracting() {
            this.draw();
        };

        _proto.needToRedraw = function needToRedraw() {
            var map = this.getMap();

            if (map.getPitch()) {
                return _CanvasRenderer.prototype.needToRedraw.call(this);
            }

            if (map.isRotating() || map.isZooming()) {
                return true;
            }

            if (map.isMoving()) {
                return !!this.layer.options['forceRenderOnMoving'];
            }

            return _CanvasRenderer.prototype.needToRedraw.call(this);
        };

        _proto.hitDetect = function hitDetect() {
            return false;
        };

        _proto._getLoadLimit = function _getLoadLimit() {
            if (this.getMap().isInteracting()) {
                return this.layer.options['loadingLimitOnInteracting'];
            }

            return 0;
        };

        _proto.isDrawable = function isDrawable() {
            if (this.getMap().getPitch()) {
                if (console) {
                    console.warn('TileLayer with canvas renderer can\'t be pitched, use gl renderer (\'renderer\' : \'gl\') instead.');
                }

                this.clear();
                return false;
            }

            return true;
        };

        _proto.clear = function clear() {
            this._retireTiles(true);

            this.tileCache.reset();
            this.tilesInView = {};
            this.tilesLoading = {};
            this._parentTiles = [];
            this._childTiles = [];

            _CanvasRenderer.prototype.clear.call(this);
        };

        _proto._isLoadingTile = function _isLoadingTile(tileId) {
            return !!this.tilesLoading[tileId];
        };

        _proto.clipCanvas = function clipCanvas(context) {
            return _CanvasRenderer.prototype.clipCanvas.call(this, context);
        };

        _proto._clipByPitch = function _clipByPitch(ctx) {
            var map = this.getMap();

            if (map.getPitch() <= map.options['maxVisualPitch']) {
                return false;
            }

            if (!this.layer.options['clipByPitch']) {
                return false;
            }

            var clipExtent = map.getContainerExtent();
            var r = map.getDevicePixelRatio();
            ctx.save();
            ctx.strokeStyle = 'rgba(0, 0, 0, 0)';
            ctx.beginPath();
            ctx.rect(0, Math.ceil(clipExtent.ymin) * r, Math.ceil(clipExtent.getWidth()) * r, Math.ceil(clipExtent.getHeight()) * r);
            ctx.stroke();
            ctx.clip();
            return true;
        };

        _proto.loadTileQueue = function loadTileQueue(tileQueue) {
            for (var p in tileQueue) {
                if (tileQueue.hasOwnProperty(p)) {
                    var tile = tileQueue[p];
                    var tileImage = this.loadTile(tile);

                    if (tileImage.loadTime === undefined) {
                        this.tilesLoading[tile['id']] = {
                            image: tileImage,
                            current: true,
                            info: tile
                        };
                    }
                }
            }
        };

        _proto.loadTile = function loadTile(tile) {
            var tileSize = this.layer.getTileSize();
            var tileImage = new Image();
            tileImage.width = tileSize['width'];
            tileImage.height = tileSize['height'];
            tileImage.onload = this.onTileLoad.bind(this, tileImage, tile);
            tileImage.onerror = this.onTileError.bind(this, tileImage, tile);
            this.loadTileImage(tileImage, tile['url']);
            return tileImage;
        };

        _proto.loadTileImage = function loadTileImage(tileImage, url) {
            var crossOrigin = this.layer.options['crossOrigin'];

            if (!isNil(crossOrigin)) {
                tileImage.crossOrigin = crossOrigin;
            }

            return loadImage(tileImage, [url]);
        };

        _proto.abortTileLoading = function abortTileLoading(tileImage) {
            if (!tileImage) return;
            tileImage.onload = falseFn;
            tileImage.onerror = falseFn;
            tileImage.src = emptyImageUrl;
        };

        _proto.onTileLoad = function onTileLoad(tileImage, tileInfo) {
            if (!this.layer) {
                return;
            }

            var id = tileInfo['id'];

            if (!this.tilesInView) {
                return;
            }

            var e = {
                tile: tileInfo,
                tileImage: tileImage
            };
            this.layer.fire('tileload', e);
            tileImage = e.tileImage;
            tileImage.loadTime = now();
            delete this.tilesLoading[id];

            this._addTileToCache(tileInfo, tileImage);

            this.setToRedraw();
        };

        _proto.onTileError = function onTileError(tileImage, tileInfo) {
            if (!this.layer) {
                return;
            }

            tileImage.onerrorTick = tileImage.onerrorTick || 0;
            var tileRetryCount = this.layer.options['tileRetryCount'];

            if (tileRetryCount > tileImage.onerrorTick) {
                tileImage.onerrorTick++;
                tileImage.src = tileInfo.url;
                return;
            }

            if (tileImage instanceof Image) {
                var errorUrl = this.layer.options['errorUrl'];

                if (errorUrl && tileImage.src !== errorUrl) {
                    tileImage.src = errorUrl;
                    return;
                }

                this.abortTileLoading(tileImage, tileInfo);
            }

            tileImage.loadTime = 0;
            delete this.tilesLoading[tileInfo['id']];

            this._addTileToCache(tileInfo, tileImage);

            this.setToRedraw();
            this.layer.fire('tileerror', {
                tile: tileInfo
            });
        };

        _proto.drawTile = function drawTile(tileInfo, tileImage) {
            if (!tileImage || !this.getMap()) {
                return;
            }

            var extent2d = tileInfo.extent2d,
                offset = tileInfo.offset;
            var point = TILE_POINT.set(extent2d.xmin - offset[0], extent2d.ymax - offset[1]),
                tileZoom = tileInfo.z,
                tileId = tileInfo.id;

            var map = this.getMap(),
                tileSize = this.layer.getTileSize(),
                zoom = map.getZoom(),
                ctx = this.context,
                cp = map._pointToContainerPoint(point, tileZoom, 0, TEMP_POINT$3),
                bearing = map.getBearing(),
                transformed = bearing || zoom !== tileZoom;

            var opacity = this.getTileOpacity(tileImage);
            var alpha = ctx.globalAlpha;

            if (opacity < 1) {
                ctx.globalAlpha = opacity;
                this.setToRedraw();
            }

            if (!transformed) {
                cp._round();
            }

            var x = cp.x,
                y = cp.y;
            var w = tileSize.width,
                h = tileSize.height;

            if (transformed) {
                ctx.save();
                ctx.translate(x, y);

                if (bearing) {
                    ctx.rotate(-bearing * Math.PI / 180);
                    w += 0.1;
                    h += 0.1;
                }

                if (zoom !== tileZoom) {
                    var scale = map._getResolution(tileZoom) / map._getResolution();

                    ctx.scale(scale, scale);
                }

                x = y = 0;
            }

            Canvas.image(ctx, tileImage, x, y, w, h);

            if (this.layer.options['debug']) {
                var color = this.layer.options['debugOutline'];
                ctx.save();
                ctx.strokeStyle = color;
                ctx.fillStyle = color;
                ctx.strokeWidth = 10;
                ctx.font = '20px monospace';

                var _point = new Point(x, y);

                Canvas.rectangle(ctx, _point, {
                    width: w,
                    height: h
                }, 1, 0);
                Canvas.fillText(ctx, this.getDebugInfo(tileId), _point._add(10, 20), color);
                Canvas.drawCross(ctx, x + w / 2, y + h / 2, 2, color);
                ctx.restore();
            }

            if (transformed) {
                ctx.restore();
            }

            if (ctx.globalAlpha !== alpha) {
                ctx.globalAlpha = alpha;
            }

            this.setCanvasUpdated();
        };

        _proto.getDebugInfo = function getDebugInfo(tileId) {
            var xyz = tileId.split('_');
            var length = xyz.length;
            return 'x:' + xyz[length - 2] + ', y:' + xyz[length - 3] + ', z:' + xyz[length - 1];
        };

        _proto._findChildTiles = function _findChildTiles(info) {
            var layer = this._getLayerOfTile(info.layer);

            if (!layer.options['background']) {
                return [];
            }

            var map = this.getMap();
            var children = [];

            var min = info.extent2d.getMin(),
                max = info.extent2d.getMax(),
                offset = info.offset,
                pmin = layer._project(map._pointToPrj(min, info.z, TEMP_POINT1$2), TEMP_POINT1$2),
                pmax = layer._project(map._pointToPrj(max, info.z, TEMP_POINT2$1), TEMP_POINT2$1);

            var zoomDiff = 2;

            for (var i = 1; i < zoomDiff; i++) {
                this._findChildTilesAt(children, pmin, pmax, layer, info.z + i, offset);
            }

            return children;
        };

        _proto._findChildTilesAt = function _findChildTilesAt(children, pmin, pmax, layer, childZoom, offset) {
            var zoomOffset = layer.options['zoomOffset'];
            var layerId = layer.getId(),
                res = layer.getSpatialReference().getResolution(childZoom + zoomOffset);

            if (!res) {
                return;
            }

            var dmin = layer._getTileConfig().getTileIndex(pmin, res, offset),
                dmax = layer._getTileConfig().getTileIndex(pmax, res, offset);

            var sx = Math.min(dmin.idx, dmax.idx),
                ex = Math.max(dmin.idx, dmax.idx);
            var sy = Math.min(dmin.idy, dmax.idy),
                ey = Math.max(dmin.idy, dmax.idy);
            var id, tile;

            for (var i = sx; i < ex; i++) {
                for (var ii = sy; ii < ey; ii++) {
                    id = layer._getTileId(i, ii, childZoom + zoomOffset, layerId);

                    if (this.tileCache.has(id)) {
                        tile = this.tileCache.getAndRemove(id);
                        children.push(tile);
                        this.tileCache.add(id, tile);
                    }
                }
            }
        };

        _proto._findParentTile = function _findParentTile(info) {
            var map = this.getMap(),
                layer = this._getLayerOfTile(info.layer);

            if (!layer.options['background']) {
                return null;
            }

            var sr = layer.getSpatialReference();
            var d = sr.getZoomDirection(),
                zoomOffset = layer.options['zoomOffset'],
                zoomDiff = layer.options['backgroundZoomDiff'];

            var center = info.extent2d.getCenter(),
                offset = info.offset,
                prj = layer._project(map._pointToPrj(center, info.z));

            for (var diff = 1; diff <= zoomDiff; diff++) {
                var z = info.z - d * diff;
                var res = sr.getResolution(z + zoomOffset);
                if (!res) continue;

                var tileIndex = layer._getTileConfig().getTileIndex(prj, res, offset);

                var id = layer._getTileId(tileIndex.x, tileIndex.y, z + zoomOffset, info.layer);

                if (this.tileCache.has(id)) {
                    var tile = this.tileCache.getAndRemove(id);
                    this.tileCache.add(id, tile);
                    return tile;
                }
            }

            return null;
        };

        _proto._getLayerOfTile = function _getLayerOfTile(layerId) {
            return this.layer.getChildLayer ? this.layer.getChildLayer(layerId) : this.layer;
        };

        _proto._getCachedTile = function _getCachedTile(tileId) {
            var tilesInView = this.tilesInView;
            var cached = this.tileCache.getAndRemove(tileId);

            if (cached) {
                tilesInView[tileId] = cached;
                var tilesLoading = this.tilesLoading;

                if (tilesLoading && tilesLoading[tileId]) {
                    tilesLoading[tileId].current = false;
                    var _tilesLoading$tileId = tilesLoading[tileId],
                        image = _tilesLoading$tileId.image,
                        info = _tilesLoading$tileId.info;
                    this.abortTileLoading(image, info);
                    delete tilesLoading[tileId];
                }
            } else {
                cached = tilesInView[tileId];
            }

            return cached;
        };

        _proto._addTileToCache = function _addTileToCache(tileInfo, tileImage) {
            this.tilesInView[tileInfo.id] = {
                image: tileImage,
                current: true,
                info: tileInfo
            };
        };

        _proto.getTileOpacity = function getTileOpacity(tileImage) {
            if (!this.layer.options['fadeAnimation'] || !tileImage.loadTime) {
                return 1;
            }

            return Math.min(1, (now() - tileImage.loadTime) / (1000 / 60 * 10));
        };

        _proto.onRemove = function onRemove() {
            this.clear();
            delete this.tileCache;
            delete this._tilePlaceHolder;

            _CanvasRenderer.prototype.onRemove.call(this);
        };

        _proto._markTiles = function _markTiles() {
            var a = 0,
                b = 0;

            if (this.tilesLoading) {
                for (var p in this.tilesLoading) {
                    this.tilesLoading[p].current = false;
                    a++;
                }
            }

            if (this.tilesInView) {
                for (var _p in this.tilesInView) {
                    this.tilesInView[_p].current = false;
                    b++;
                }
            }

            return [a, b];
        };

        _proto._retireTiles = function _retireTiles(force) {
            for (var i in this.tilesLoading) {
                var tile = this.tilesLoading[i];

                if (force || !tile.current) {
                    if (tile.image) {
                        this.abortTileLoading(tile.image, tile.info);
                    }

                    this.deleteTile(tile);
                    delete this.tilesLoading[i];
                }
            }

            for (var _i2 in this.tilesInView) {
                var _tile = this.tilesInView[_i2];

                if (!_tile.current) {
                    delete this.tilesInView[_i2];

                    if (!this.tileCache.has(_i2)) {
                        this.deleteTile(_tile);
                    }
                }
            }
        };

        _proto.deleteTile = function deleteTile(tile) {
            if (!tile || !tile.image) {
                return;
            }

            tile.image.onload = null;
            tile.image.onerror = null;
        };

        _proto._generatePlaceHolder = function _generatePlaceHolder(z) {
            var map = this.getMap();
            var placeholder = this.layer.options['placeholder'];

            if (!placeholder || map.getPitch()) {
                return null;
            }

            var tileSize = this.layer.getTileSize(),
                scale = map._getResolution(z) / map._getResolution(),
                canvas = this._tilePlaceHolder = this._tilePlaceHolder || Canvas.createCanvas(1, 1, map.CanvasClass);

            canvas.width = tileSize.width * scale;
            canvas.height = tileSize.height * scale;

            if (isFunction(placeholder)) {
                placeholder(canvas);
            } else {
                defaultPlaceholder(canvas);
            }

            return canvas;
        };

        return TileLayerCanvasRenderer;
    }(CanvasRenderer);

    TileLayer.registerRenderer('canvas', TileLayerCanvasRenderer);

    function falseFn() {
        return false;
    }

    function defaultPlaceholder(canvas) {
        var ctx = canvas.getContext('2d'),
            cw = canvas.width,
            ch = canvas.height,
            w = cw / 16,
            h = ch / 16;
        ctx.beginPath();

        for (var i = 0; i < 16; i++) {
            ctx.moveTo(0, i * h);
            ctx.lineTo(cw, i * h);
            ctx.moveTo(i * w, 0);
            ctx.lineTo(i * w, ch);
        }

        ctx.strokeStyle = 'rgba(180, 180, 180, 0.1)';
        ctx.lineWidth = 1;
        ctx.stroke();
        ctx.beginPath();
        var path = [
            [0, 0],
            [cw, 0],
            [0, ch],
            [cw, ch],
            [0, 0],
            [0, ch],
            [cw, 0],
            [cw, ch],
            [0, ch / 2],
            [cw, ch / 2],
            [cw / 2, 0],
            [cw / 2, ch]
        ];

        for (var _i3 = 1; _i3 < path.length; _i3 += 2) {
            ctx.moveTo(path[_i3 - 1][0], path[_i3 - 1][1]);
            ctx.lineTo(path[_i3][0], path[_i3][1]);
        }

        ctx.lineWidth = 1 * 4;
        ctx.stroke();
    }

    var TILE_POINT$1 = new Point(0, 0);

    var TileLayerGLRenderer = function(_ImageGLRenderable) {
        _inheritsLoose(TileLayerGLRenderer, _ImageGLRenderable);

        function TileLayerGLRenderer() {
            return _ImageGLRenderable.apply(this, arguments) || this;
        }

        var _proto = TileLayerGLRenderer.prototype;

        _proto.isDrawable = function isDrawable() {
            return true;
        };

        _proto.needToRedraw = function needToRedraw() {
            var map = this.getMap();

            if (this._gl() && !map.getPitch() && map.isZooming() && !map.isMoving() && !map.isRotating()) {
                return true;
            }

            return _ImageGLRenderable.prototype.needToRedraw.call(this);
        };

        _proto.drawTile = function drawTile(tileInfo, tileImage) {
            var map = this.getMap();

            if (!tileInfo || !map || !tileImage) {
                return;
            }

            var scale = tileInfo._glScale = tileInfo._glScale || map.getGLScale(tileInfo.z);
            var size = this.layer.getTileSize();
            var w = size.width;
            var h = size.height;

            if (tileInfo.cache !== false) {
                this._bindGLBuffer(tileImage, w, h);
            }

            if (!this._gl()) {
                _ImageGLRenderable.prototype.drawTile.call(this, tileInfo, tileImage);

                return;
            }

            var extent2d = tileInfo.extent2d,
                offset = tileInfo.offset;
            var point = TILE_POINT$1.set(extent2d.xmin - offset[0], tileInfo.extent2d.ymax - offset[1]);
            var x = point.x * scale,
                y = point.y * scale;
            var opacity = this.getTileOpacity(tileImage);
            var debugInfo = null;

            if (this.layer.options['debug']) {
                debugInfo = this.getDebugInfo(tileInfo.id);
            }

            this.drawGLImage(tileImage, x, y, w, h, scale, opacity, debugInfo);

            if (opacity < 1) {
                this.setToRedraw();
            } else {
                this.setCanvasUpdated();
            }
        };

        _proto.writeZoomStencil = function writeZoomStencil() {
            var gl = this.gl;
            gl.stencilFunc(gl.ALWAYS, 1, 0xFF);
            gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
        };

        _proto.startZoomStencilTest = function startZoomStencilTest() {
            var gl = this.gl;
            gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
            gl.stencilFunc(gl.EQUAL, 0, 0xFF);
        };

        _proto.endZoomStencilTest = function endZoomStencilTest() {
            this.pauseZoomStencilTest();
        };

        _proto.pauseZoomStencilTest = function pauseZoomStencilTest() {
            var gl = this.gl;
            gl.stencilFunc(gl.ALWAYS, 1, 0xFF);
        };

        _proto.resumeZoomStencilTest = function resumeZoomStencilTest() {
            var gl = this.gl;
            gl.stencilFunc(gl.EQUAL, 0, 0xFF);
        };

        _proto._bindGLBuffer = function _bindGLBuffer(image, w, h) {
            if (!image.glBuffer) {
                image.glBuffer = this.bufferTileData(0, 0, w, h);
            }
        };

        _proto.loadTileImage = function loadTileImage(tileImage, url) {
            var crossOrigin = this.layer.options['crossOrigin'];
            tileImage.crossOrigin = crossOrigin !== null ? crossOrigin : '';
            tileImage.src = url;
            return;
        };

        _proto.onCanvasCreate = function onCanvasCreate() {
            if (!this.canvas.gl || !this.canvas.gl.wrap) {
                this.createCanvas2();
            }
        };

        _proto.createContext = function createContext() {
            _ImageGLRenderable.prototype.createContext.call(this);

            this.createGLContext();
        };

        _proto.resizeCanvas = function resizeCanvas(canvasSize) {
            if (!this.canvas) {
                return;
            }

            _ImageGLRenderable.prototype.resizeCanvas.call(this, canvasSize);

            this.resizeGLCanvas();
        };

        _proto.clearCanvas = function clearCanvas() {
            if (!this.canvas) {
                return;
            }

            _ImageGLRenderable.prototype.clearCanvas.call(this);

            this.clearGLCanvas();
        };

        _proto.getCanvasImage = function getCanvasImage() {
            if (!this._gl() || !this.canvas2) {
                return _ImageGLRenderable.prototype.getCanvasImage.call(this);
            }

            var img = _ImageGLRenderable.prototype.getCanvasImage.call(this);

            if (img) {
                img.image = this.canvas2;
            }

            return img;
        };

        _proto._gl = function _gl() {
            if (this.canvas.gl && this.canvas.gl.wrap) {
                return true;
            }

            var map = this.getMap();
            return map && (map.getPitch() || map.getBearing()) || this.layer && !!this.layer.options['fragmentShader'];
        };

        _proto.deleteTile = function deleteTile(tile) {
            _ImageGLRenderable.prototype.deleteTile.call(this, tile);

            if (tile && tile.image) {
                this.disposeImage(tile.image);
            }

            delete tile.image;
        };

        _proto.onRemove = function onRemove() {
            _ImageGLRenderable.prototype.onRemove.call(this);

            this.removeGLCanvas();
        };

        return TileLayerGLRenderer;
    }(ImageGLRenderable(TileLayerCanvasRenderer));

    TileLayer.registerRenderer('gl', TileLayerGLRenderer);

    function _loadTile(tile) {
        var tileSize = this.layer.getTileSize(),
            canvasClass = this.canvas.constructor,
            map = this.getMap();
        var r = map.getDevicePixelRatio();
        var tileCanvas = Canvas.createCanvas(tileSize['width'] * r, tileSize['height'] * r, canvasClass);
        tileCanvas['layer'] = this.layer;
        var me = this;
        var point = new Point(tile['extent2d'].xmin, tile['extent2d'].ymax);
        var extent = new Extent(map.pointToCoordinate(point), map.pointToCoordinate(point.add(tileSize.width, tileSize.height)), map.getProjection());
        this.layer.drawTile(tileCanvas, {
            'url': tile['url'],
            'point': point,
            'center': map.pointToCoordinate(point.add(tileSize['width'] / 2, tileSize['height'] / 2)),
            'extent': extent,
            'z': tile['z'],
            'x': tile['x'],
            'y': tile['y']
        }, function(error) {
            if (error) {
                me.onTileError(tileCanvas, tile);
                return;
            }

            me.onTileLoad(tileCanvas, tile);
        });
        return tileCanvas;
    }

    var CanvasRenderer$1 = function(_TileLayerCanvasRende) {
        _inheritsLoose(CanvasRenderer, _TileLayerCanvasRende);

        function CanvasRenderer() {
            return _TileLayerCanvasRende.apply(this, arguments) || this;
        }

        var _proto = CanvasRenderer.prototype;

        _proto.loadTile = function loadTile() {
            return _loadTile.apply(this, arguments);
        };

        return CanvasRenderer;
    }(TileLayerCanvasRenderer);

    var GLRenderer = function(_TileLayerGLRenderer) {
        _inheritsLoose(GLRenderer, _TileLayerGLRenderer);

        function GLRenderer() {
            return _TileLayerGLRenderer.apply(this, arguments) || this;
        }

        var _proto2 = GLRenderer.prototype;

        _proto2.loadTile = function loadTile() {
            return _loadTile.apply(this, arguments);
        };

        return GLRenderer;
    }(TileLayerGLRenderer);

    CanvasTileLayer.registerRenderer('canvas', CanvasRenderer$1);
    CanvasTileLayer.registerRenderer('gl', GLRenderer);

    var OverlayLayerRenderer = function(_CanvasRenderer) {
        _inheritsLoose(OverlayLayerRenderer, _CanvasRenderer);

        function OverlayLayerRenderer() {
            return _CanvasRenderer.apply(this, arguments) || this;
        }

        var _proto = OverlayLayerRenderer.prototype;

        _proto.checkResources = function checkResources() {
            var geometries = this._geosToCheck;

            if (!this._resourceChecked && !geometries) {
                geometries = this.layer._geoList;
            }

            if (!isArrayHasData(geometries)) {
                return [];
            }

            var resources = [];
            var cache = {};

            for (var i = geometries.length - 1; i >= 0; i--) {
                var geo = geometries[i];

                var res = geo._getExternalResources();

                if (!res.length) {
                    continue;
                }

                if (!this.resources) {
                    resources.push.apply(resources, res);
                } else {
                    for (var _i = 0; _i < res.length; _i++) {
                        var url = res[_i][0];

                        if (!this.resources.isResourceLoaded(res[_i]) && !cache[url]) {
                            resources.push(res[_i]);
                            cache[url] = 1;
                        }
                    }
                }
            }

            this._resourceChecked = true;
            delete this._geosToCheck;
            return resources;
        };

        _proto.render = function render() {
            this.layer._sortGeometries();

            return _CanvasRenderer.prototype.render.apply(this, arguments);
        };

        _proto._addGeoToCheckRes = function _addGeoToCheckRes(res) {
            if (!res) {
                return;
            }

            if (!Array.isArray(res)) {
                res = [res];
            }

            if (!this._geosToCheck) {
                this._geosToCheck = [];
            }

            pushIn(this._geosToCheck, res);
        };

        _proto.onGeometryAdd = function onGeometryAdd(geometries) {
            this._addGeoToCheckRes(geometries);

            redraw(this);
        };

        _proto.onGeometryRemove = function onGeometryRemove() {
            redraw(this);
        };

        _proto.onGeometrySymbolChange = function onGeometrySymbolChange(e) {
            this._addGeoToCheckRes(e.target);

            redraw(this);
        };

        _proto.onGeometryShapeChange = function onGeometryShapeChange() {
            redraw(this);
        };

        _proto.onGeometryPositionChange = function onGeometryPositionChange() {
            redraw(this);
        };

        _proto.onGeometryZIndexChange = function onGeometryZIndexChange() {
            redraw(this);
        };

        _proto.onGeometryShow = function onGeometryShow() {
            redraw(this);
        };

        _proto.onGeometryHide = function onGeometryHide() {
            redraw(this);
        };

        _proto.onGeometryPropertiesChange = function onGeometryPropertiesChange() {
            redraw(this);
        };

        return OverlayLayerRenderer;
    }(CanvasRenderer);

    function redraw(renderer) {
        if (renderer.layer.options['drawImmediate']) {
            renderer.render();
        }

        renderer.setToRedraw();
    }

    var TEMP_EXTENT$4 = new PointExtent();

    var VectorLayerRenderer = function(_OverlayLayerCanvasRe) {
        _inheritsLoose(VectorLayerRenderer, _OverlayLayerCanvasRe);

        function VectorLayerRenderer() {
            return _OverlayLayerCanvasRe.apply(this, arguments) || this;
        }

        var _proto = VectorLayerRenderer.prototype;

        _proto.checkResources = function checkResources() {
            var _this = this;

            var resources = _OverlayLayerCanvasRe.prototype.checkResources.apply(this, arguments);

            var style = this.layer.getStyle();

            if (style) {
                if (!Array.isArray(style)) {
                    style = [style];
                }

                style.forEach(function(s) {
                    var res = getExternalResources(s['symbol'], true);

                    for (var i = 0, l = res.length; i < l; i++) {
                        if (!_this.resources.isResourceLoaded(res[i])) {
                            resources.push(res[i]);
                        }
                    }
                });
            }

            return resources;
        };

        _proto.needToRedraw = function needToRedraw() {
            var map = this.getMap();

            if (map.isInteracting() && this.layer.options['enableAltitude']) {
                return true;
            }

            if (map.isZooming() && !map.isRotating() && !map.getPitch() && !this._hasPoint && this.layer.constructor === VectorLayer) {
                return false;
            }

            return _OverlayLayerCanvasRe.prototype.needToRedraw.call(this);
        };

        _proto.draw = function draw() {
            if (!this.getMap()) {
                return;
            }

            if (!this.layer.isVisible() || this.layer.isEmpty()) {
                this.clearCanvas();
                this.completeRender();
                return;
            }

            this.prepareCanvas();
            this.drawGeos();
            this.completeRender();
        };

        _proto.isBlank = function isBlank() {
            if (!this.context) {
                return false;
            }

            return !this.context.canvas._drawn;
        };

        _proto.drawOnInteracting = function drawOnInteracting() {
            if (!this._geosToDraw) {
                return;
            }

            this._updateDisplayExtent();

            var map = this.getMap();
            var count = this.layer.getCount();
            var res = this.getMap().getResolution();

            if (map.isZooming() && map.options['seamlessZoom'] && this._drawnRes !== undefined && res > this._drawnRes * 1.5 && this._geosToDraw.length < count || map.isMoving() || map.isInteracting()) {
                this.prepareToDraw();
                this.forEachGeo(this.checkGeo, this);
                this._drawnRes = res;
            }

            for (var i = 0, l = this._geosToDraw.length; i < l; i++) {
                var geo = this._geosToDraw[i];

                if (!geo.isVisible()) {
                    continue;
                }

                geo._paint(this._displayExtent);
            }
        };

        _proto.show = function show() {
            this.layer.forEach(function(geo) {
                geo._repaint();
            });

            _OverlayLayerCanvasRe.prototype.show.apply(this, arguments);
        };

        _proto.forEachGeo = function forEachGeo(fn, context) {
            this.layer.forEach(fn, context);
        };

        _proto.drawGeos = function drawGeos() {

            this._drawnRes = this.getMap().getResolution();

            this._updateDisplayExtent();

            this.prepareToDraw();
            this.forEachGeo(this.checkGeo, this);

            for (var i = 0, len = this._geosToDraw.length; i < len; i++) {
                this._geosToDraw[i]._paint();
            }
        };

        _proto.prepareToDraw = function prepareToDraw() {
            this._hasPoint = false;
            this._geosToDraw = [];
        };

        _proto.checkGeo = function checkGeo(geo) {
            if (!geo || !geo.isVisible() || !geo.getMap() || !geo.getLayer() || !geo.getLayer().isCanvasRender()) {
                return;
            }

            var painter = geo._getPainter();

            var extent2D = painter.get2DExtent(this.resources, TEMP_EXTENT$4);

            if (!extent2D || !extent2D.intersects(this._displayExtent)) {
                return;
            }

            if (painter.hasPoint()) {
                this._hasPoint = true;
            }

            this._geosToDraw.push(geo);
        };

        _proto.onZoomEnd = function onZoomEnd() {
            delete this.canvasExtent2D;

            _OverlayLayerCanvasRe.prototype.onZoomEnd.apply(this, arguments);
        };

        _proto.onRemove = function onRemove() {
            this.forEachGeo(function(g) {
                g.onHide();
            });
            delete this._geosToDraw;
        };

        _proto.onGeometryPropertiesChange = function onGeometryPropertiesChange(param) {
            if (param) {
                this.layer._styleGeometry(param['target']);
            }

            _OverlayLayerCanvasRe.prototype.onGeometryPropertiesChange.call(this, param);
        };

        _proto._updateDisplayExtent = function _updateDisplayExtent() {
            var extent2D = this.canvasExtent2D;

            if (this._maskExtent) {
                if (!this._maskExtent.intersects(extent2D)) {
                    this.completeRender();
                    return;
                }

                extent2D = extent2D.intersection(this._maskExtent);
            }

            this._displayExtent = extent2D;
        };

        _proto.identify = function identify(coordinate, options) {
            if (options === void 0) {
                options = {};
            }

            var geometries = this._geosToDraw;

            if (!geometries) {
                return [];
            }

            return this.layer._hitGeos(geometries, coordinate, options);
        };

        return VectorLayerRenderer;
    }(OverlayLayerRenderer);

    VectorLayer.registerRenderer('canvas', VectorLayerRenderer);

    var MapRenderer = function(_Class) {
        _inheritsLoose(MapRenderer, _Class);

        function MapRenderer(map) {
            var _this;

            _this = _Class.call(this) || this;
            _this.map = map;
            _this._handlerQueue = {};
            return _this;
        }

        var _proto = MapRenderer.prototype;

        _proto.callInNextFrame = function callInNextFrame(fn) {
            this._handlerQueue.push(fn);
        };

        _proto.executeFrameCallbacks = function executeFrameCallbacks() {
            var running = this._handlerQueue;
            this._handlerQueue = [];

            for (var i = 0, l = running.length; i < l; i++) {
                running[i]();
            }
        };

        _proto.offsetPlatform = function offsetPlatform(offset, force) {
            if (!this.map._panels.front) {
                return this;
            }

            if (!force && offset.x === 0 && offset.y === 0) {
                return this;
            }

            var panels = this.map._panels;
            var hasFront = this._frontCount = panels.back.layerDOM.childElementCount;
            var hasBack = this._backCount = panels.front.layerDOM.childElementCount;
            var hasUI = this._uiCount = panels.front.uiDOM.childElementCount;

            if (hasFront || hasBack || hasUI) {
                var pos = this.map.offsetPlatform();

                if (offset) {
                    pos = pos.add(offset)._round();
                } else {
                    pos = pos.round();
                }

                if (hasBack) {
                    offsetDom(panels.back, pos);
                }

                if (hasFront || hasUI) {
                    offsetDom(panels.front, pos);
                }
            }

            return this;
        };

        _proto.domChanged = function domChanged() {
            var panels = this.map._panels;

            if (!panels.front) {
                return false;
            }

            var frontCount = panels.back.layerDOM.childElementCount;

            if (this._frontCount === undefined || this._frontCount !== frontCount) {
                return true;
            }

            var backCount = panels.front.layerDOM.childElementCount;

            if (this._backCount === undefined || this._backCount !== backCount) {
                return true;
            }

            var uiCount = panels.front.uiDOM.childElementCount;

            if (this._uiCount === undefined || this._uiCount !== uiCount) {
                return true;
            }

            return false;
        };

        _proto.resetContainer = function resetContainer() {
            if (!this.map) {
                return;
            }

            this.map._resetMapViewPoint();

            if (this.map._panels.front) {
                var pos = new Point(0, 0);
                offsetDom(this.map._panels.back, pos);
                offsetDom(this.map._panels.front, pos);
            }
        };

        _proto.onZoomEnd = function onZoomEnd() {
            this.resetContainer();
        };

        _proto.onLoad = function onLoad() {
            this._frameLoop();
        };

        return MapRenderer;
    }(Class);

    var MapCanvasRenderer = function(_MapRenderer) {
        _inheritsLoose(MapCanvasRenderer, _MapRenderer);

        function MapCanvasRenderer(map) {
            var _this;

            _this = _MapRenderer.call(this, map) || this;
            _this._containerIsCanvas = !!map._containerDOM.getContext;
            _this._thisVisibilitychange = _this._onVisibilitychange.bind(_assertThisInitialized(_assertThisInitialized(_this)));

            _this._registerEvents();

            _this._loopTime = 0;
            return _this;
        }

        var _proto = MapCanvasRenderer.prototype;

        _proto.load = function load() {
            this.initContainer();
        };

        _proto.renderFrame = function renderFrame(framestamp) {
            if (!this.map) {
                return false;
            }

            delete this._isViewChanged;
            var map = this.map;

            map._fireEvent('framestart');

            this.updateMapDOM();

            var layers = this._getAllLayerToRender();

            this.drawLayers(layers, framestamp);
            var updated = this.drawLayerCanvas(layers);

            if (updated) {
                this._drawCenterCross();
            }

            map._fireEvent('frameend');

            this._recordView();

            this._mapview = this._getMapView();
            delete this._spatialRefChanged;

            this._fireLayerLoadEvents();

            this.executeFrameCallbacks();
            this._canvasUpdated = false;
            return true;
        };

        _proto.updateMapDOM = function updateMapDOM() {
            var map = this.map;

            if (map.isZooming()) {
                return;
            }

            var offset = map._getViewPointFrameOffset();

            if (offset) {
                map.offsetPlatform(offset);
            } else if (this.domChanged()) {
                this.offsetPlatform(null, true);
            }
        };

        _proto.drawLayers = function drawLayers(layers, framestamp) {
            var map = this.map,
                isInteracting = map.isInteracting(),
                canvasIds = [],
                updatedIds = [],
                fps = map.options['fpsOnInteracting'] || 0,
                timeLimit = fps === 0 ? 0 : 1000 / fps,
                layerLimit = this.map.options['layerCanvasLimitOnInteracting'],
                l = layers.length;
            var baseLayer = map.getBaseLayer();
            var t = 0;

            for (var i = 0; i < l; i++) {
                var layer = layers[i];

                if (!layer.isVisible()) {
                    continue;
                }

                var isCanvas = layer.isCanvasRender();

                if (isCanvas) {
                    canvasIds.push(layer.getId());
                }

                var renderer = layer._getRenderer();

                if (!renderer) {
                    continue;
                }

                var needsRedraw = this._checkLayerRedraw(layer);

                if (isCanvas && renderer.isCanvasUpdated()) {
                    if (!needsRedraw) {
                        updatedIds.push(layer.getId());
                    }

                    this.setLayerCanvasUpdated();
                }

                var transformMatrix = renderer.__zoomTransformMatrix;
                delete renderer.__zoomTransformMatrix;

                if (!needsRedraw) {
                    if (isCanvas && isInteracting) {
                        if (map.isZooming() && !map.getPitch()) {
                            renderer.prepareRender();
                            renderer.__zoomTransformMatrix = this._zoomMatrix;
                        } else if (map.getPitch() || map.isRotating()) {
                            renderer.clearCanvas();
                        }
                    }

                    continue;
                }

                if (isInteracting && isCanvas) {
                    if (layerLimit > 0 && l - 1 - i > layerLimit && layer !== baseLayer) {
                        layer._getRenderer().clearCanvas();

                        continue;
                    }

                    t += this._drawCanvasLayerOnInteracting(layer, t, timeLimit, framestamp);
                } else if (isInteracting && renderer.drawOnInteracting) {
                    if (renderer.prepareRender) {
                        renderer.prepareRender();
                    }

                    if (renderer.checkAndDraw) {
                        renderer.checkAndDraw(renderer.drawOnInteracting, this._eventParam, framestamp);
                    } else {
                        renderer.drawOnInteracting(this._eventParam, framestamp);
                    }
                } else {
                    renderer.render(framestamp);

                    if (isCanvas && transformMatrix && renderer.isLoadingResource()) {
                        renderer.__zoomTransformMatrix = transformMatrix;
                    }
                }

                if (isCanvas) {
                    updatedIds.push(layer.getId());
                    this.setLayerCanvasUpdated();
                }
            }

            var preCanvasIds = this._canvasIds || [];
            var preUpdatedIds = this._updatedIds || [];
            this._canvasIds = canvasIds;
            this._updatedIds = updatedIds;

            if (!this.isLayerCanvasUpdated()) {
                var sep = '---';

                if (preCanvasIds.join(sep) !== canvasIds.join(sep) || preUpdatedIds.join(sep) !== updatedIds.join(sep)) {
                    this.setLayerCanvasUpdated();
                }
            }
        };

        _proto._checkLayerRedraw = function _checkLayerRedraw(layer) {
            if (this.isSpatialReferenceChanged()) {
                return true;
            }

            var map = this.map;

            var renderer = layer._getRenderer();

            if (layer.isCanvasRender()) {
                return renderer.testIfNeedRedraw();
            } else {
                if (renderer.needToRedraw && renderer.needToRedraw()) {
                    return true;
                }

                return map.isInteracting() || this.isViewChanged();
            }
        };

        _proto._drawCanvasLayerOnInteracting = function _drawCanvasLayerOnInteracting(layer, t, timeLimit, framestamp) {
            var map = this.map,
                renderer = layer._getRenderer(),
                drawTime = renderer.getDrawTime(),
                inTime = timeLimit === 0 || timeLimit > 0 && t + drawTime <= timeLimit;

            if (renderer.mustRenderOnInteracting && renderer.mustRenderOnInteracting()) {
                renderer.render(framestamp);
            } else if (renderer.drawOnInteracting && (layer === map.getBaseLayer() || inTime || map.isZooming() && layer.options['forceRenderOnZooming'] || map.isMoving() && layer.options['forceRenderOnMoving'] || map.isRotating() && layer.options['forceRenderOnRotating'])) {
                renderer.prepareRender();
                renderer.prepareCanvas();

                if (renderer.checkAndDraw) {
                    renderer.checkAndDraw(renderer.drawOnInteracting, this._eventParam, framestamp);
                } else {
                    renderer.drawOnInteracting(this._eventParam, framestamp);
                }

                return drawTime;
            } else if (map.isZooming() && !map.getPitch() && !map.isRotating()) {
                renderer.prepareRender();
                renderer.__zoomTransformMatrix = this._zoomMatrix;
            } else if (map.getPitch() || map.isRotating()) {
                renderer.clearCanvas();
            }

            if (renderer.drawOnInteracting && !inTime) {
                renderer.onSkipDrawOnInteracting(this._eventParam, framestamp);
            }

            return 0;
        };

        _proto._fireLayerLoadEvents = function _fireLayerLoadEvents() {
            if (this._updatedIds && this._updatedIds.length > 0) {
                var map = this.map;

                this._updatedIds.reverse().forEach(function(id) {
                    var layer = map.getLayer(id);

                    if (!layer) {
                        return;
                    }

                    var renderer = layer._getRenderer();

                    if (!renderer || !renderer.isRenderComplete()) {
                        return;
                    }

                    layer.fire('layerload');
                });
            }
        };

        _proto.isLayerCanvasUpdated = function isLayerCanvasUpdated() {
            return this._canvasUpdated;
        };

        _proto.setLayerCanvasUpdated = function setLayerCanvasUpdated() {
            this._canvasUpdated = true;
        };

        _proto.drawLayerCanvas = function drawLayerCanvas(layers) {
            var map = this.map;

            if (!map) {
                return false;
            }

            if (!this.isLayerCanvasUpdated() && !this.isViewChanged()) {
                return false;
            }

            if (!this.canvas) {
                this.createCanvas();
            }

            map._fireEvent('renderstart', {
                'context': this.context
            });

            if (!this._updateCanvasSize()) {
                this.clearCanvas();
            }

            var interacting = map.isInteracting(),
                limit = map.options['layerCanvasLimitOnInteracting'];
            var len = layers.length;
            var baseLayerImage;
            var images = [];

            for (var i = 0; i < len; i++) {
                if (!layers[i].isVisible() || !layers[i].isCanvasRender()) {
                    continue;
                }

                var renderer = layers[i]._getRenderer();

                if (!renderer) {
                    continue;
                }

                var layerImage = this._getLayerImage(layers[i]);

                if (layerImage && layerImage['image']) {
                    if (layers[i] === map.getBaseLayer()) {
                        baseLayerImage = [layers[i], layerImage];
                    } else {
                        images.push([layers[i], layerImage]);
                    }
                }
            }

            if (baseLayerImage) {
                this._drawLayerCanvasImage(baseLayerImage[0], baseLayerImage[1]);

                this._drawFog();
            }

            len = images.length;
            var start = interacting && limit >= 0 && len > limit ? len - limit : 0;

            for (var _i = start; _i < len; _i++) {
                this._drawLayerCanvasImage(images[_i][0], images[_i][1]);
            }

            map._fireEvent('renderend', {
                'context': this.context
            });

            return true;
        };

        _proto.setToRedraw = function setToRedraw() {
            var layers = this._getAllLayerToRender();

            for (var i = 0, l = layers.length; i < l; i++) {
                var renderer = layers[i].getRenderer();

                if (renderer && renderer.canvas && renderer.setToRedraw) {
                    renderer.setToRedraw();
                }
            }
        };

        _proto.updateMapSize = function updateMapSize(size) {
            if (!size || this._containerIsCanvas) {
                return;
            }

            var width = size['width'] + 'px',
                height = size['height'] + 'px';
            var panels = this.map._panels;
            panels.mapWrapper.style.width = width;
            panels.mapWrapper.style.height = height;

            this._updateCanvasSize();
        };

        _proto.getMainPanel = function getMainPanel() {
            if (!this.map) {
                return null;
            }

            if (this._containerIsCanvas) {
                return this.map._containerDOM;
            }

            if (this.map._panels) {
                return this.map._panels.mapWrapper;
            }

            return null;
        };

        _proto.toDataURL = function toDataURL(mimeType) {
            if (!this.canvas) {
                return null;
            }

            return this.canvas.toDataURL(mimeType);
        };

        _proto.remove = function remove() {
            if (Browser$1.webgl && typeof document !== 'undefined') {
                removeDomEvent(document, 'visibilitychange', this._thisVisibilitychange, this);
            }

            if (this._resizeInterval) {
                clearInterval(this._resizeInterval);
            }

            delete this.context;
            delete this.canvas;
            delete this.map;
            delete this._spatialRefChanged;

            this._cancelFrameLoop();
        };

        _proto.hitDetect = function hitDetect(point) {
            var map = this.map;

            if (!map || !map.options['hitDetect'] || map.isInteracting()) {
                return;
            }

            var layers = map._getLayers();

            var cursor = 'default';
            var limit = map.options['hitDetectLimit'] || 0;
            var counter = 0;

            for (var i = layers.length - 1; i >= 0; i--) {
                var layer = layers[i];

                if (!layer.options['hitDetect'] || layer.isEmpty && layer.isEmpty()) {
                    continue;
                }

                var renderer = layer._getRenderer();

                if (!renderer || !renderer.hitDetect) {
                    continue;
                }

                if (renderer.isBlank && renderer.isBlank()) {
                    continue;
                }

                if (layer.options['cursor'] !== 'default' && renderer.hitDetect(point)) {
                    cursor = layer.options['cursor'] || 'pointer';
                    break;
                }

                counter++;

                if (limit > 0 && counter > limit) {
                    break;
                }
            }

            map._trySetCursor(cursor);
        };

        _proto._getLayerImage = function _getLayerImage(layer) {
            var renderer = layer._getRenderer();

            if (renderer.getCanvasImage) {
                return renderer.getCanvasImage();
            }

            return null;
        };

        _proto.initContainer = function initContainer() {
            var panels = this.map._panels;

            function createContainer(name, className, cssText, enableSelect) {
                var c = createEl('div', className);

                if (cssText) {
                    c.style.cssText = cssText;
                }

                panels[name] = c;

                if (!enableSelect) {
                    preventSelection(c);
                }

                return c;
            }

            var containerDOM = this.map._containerDOM;

            if (this._containerIsCanvas) {
                return;
            }

            containerDOM.innerHTML = '';
            var POSITION0 = 'position:absolute;top:0px;left:0px;';
            var mapWrapper = createContainer('mapWrapper', 'maptalks-wrapper', 'position:absolute;overflow:hidden;', true),
                mapAllLayers = createContainer('allLayers', 'maptalks-all-layers', POSITION0 + 'padding:0px;margin:0px;z-index:0;overflow:visible;', true),
                backStatic = createContainer('backStatic', 'maptalks-back-static', POSITION0 + 'z-index:0;', true),
                back = createContainer('back', 'maptalks-back', POSITION0 + 'z-index:1;'),
                backLayer = createContainer('backLayer', 'maptalks-back-layer', POSITION0),
                canvasContainer = createContainer('canvasContainer', 'maptalks-canvas-layer', POSITION0 + 'border:none;z-index:2;'),
                frontStatic = createContainer('frontStatic', 'maptalks-front-static', POSITION0 + 'z-index:3;', true),
                front = createContainer('front', 'maptalks-front', POSITION0 + 'z-index:4;', true),
                frontLayer = createContainer('frontLayer', 'maptalks-front-layer', POSITION0 + 'z-index:0;'),
                ui = createContainer('ui', 'maptalks-ui', POSITION0 + 'border:none;z-index:1;', true),
                control = createContainer('control', 'maptalks-control', 'z-index:1', true);
            containerDOM.appendChild(mapWrapper);
            mapAllLayers.appendChild(backStatic);
            back.appendChild(backLayer);
            back.layerDOM = backLayer;
            mapAllLayers.appendChild(back);
            mapAllLayers.appendChild(canvasContainer);
            front.appendChild(frontLayer);
            front.layerDOM = frontLayer;
            front.uiDOM = ui;
            mapAllLayers.appendChild(frontStatic);
            mapAllLayers.appendChild(front);
            front.appendChild(ui);
            mapWrapper.appendChild(mapAllLayers);
            mapWrapper.appendChild(control);
            this.createCanvas();
            this.resetContainer();

            var mapSize = this.map._getContainerDomSize();

            this.updateMapSize(mapSize);
        };

        _proto.isViewChanged = function isViewChanged() {
            if (this._isViewChanged !== undefined) {
                return this._isViewChanged;
            }

            var previous = this._mapview;

            var view = this._getMapView();

            this._isViewChanged = !previous || !equalMapView(previous, view);
            return this._isViewChanged;
        };

        _proto._recordView = function _recordView() {
            var map = this.map;

            if (!map._onViewChange || map.isInteracting() || map.isAnimating()) {
                return;
            }

            if (!equalMapView(map.getView(), map._getCurrentView())) {
                map._onViewChange(map.getView());
            }
        };

        _proto.isSpatialReferenceChanged = function isSpatialReferenceChanged() {
            return this._spatialRefChanged;
        };

        _proto._getMapView = function _getMapView() {
            var map = this.map;

            var center = map._getPrjCenter();

            return {
                x: center.x,
                y: center.y,
                zoom: map.getZoom(),
                pitch: map.getPitch(),
                bearing: map.getBearing(),
                width: map.width,
                height: map.height
            };
        };

        _proto._frameLoop = function _frameLoop(framestamp) {
            var _this2 = this;

            if (!this.map) {
                this._cancelFrameLoop();

                return;
            }

            this.renderFrame(framestamp);
            this._animationFrame = requestAnimFrame(function(framestamp) {
                _this2._frameLoop(framestamp);
            });
        };

        _proto._cancelFrameLoop = function _cancelFrameLoop() {
            if (this._animationFrame) {
                cancelAnimFrame(this._animationFrame);
            }
        };

        _proto._drawLayerCanvasImage = function _drawLayerCanvasImage(layer, layerImage) {
            var ctx = this.context;
            var point = layerImage['point'].round();
            var dpr = this.map.getDevicePixelRatio();

            if (dpr !== 1) {
                point._multi(dpr);
            }

            var canvasImage = layerImage['image'];
            var width = canvasImage.width,
                height = canvasImage.height;

            if (point.x + width <= 0 || point.y + height <= 0) {
                return;
            }

            var op = layer.options['opacity'];

            if (!isNumber(op)) {
                op = 1;
            }

            if (op <= 0) {
                return;
            }

            var imgOp = layerImage['opacity'];

            if (!isNumber(imgOp)) {
                imgOp = 1;
            }

            if (imgOp <= 0) {
                return;
            }

            var alpha = ctx.globalAlpha;

            if (op < 1) {
                ctx.globalAlpha *= op;
            }

            if (imgOp < 1) {
                ctx.globalAlpha *= imgOp;
            }

            if (layer.options['cssFilter']) {
                ctx.filter = layer.options['cssFilter'];
            }

            var renderer = layer.getRenderer();
            var matrix = renderer.__zoomTransformMatrix;
            var clipped = renderer.clipCanvas(this.context);

            if (matrix) {
                ctx.save();
                ctx.setTransform.apply(ctx, matrix);
            }

            ctx.drawImage(canvasImage, 0, 0, width, height, point.x, point.y, width, height);

            if (matrix) {
                ctx.restore();
            }

            if (clipped) {
                ctx.restore();
            }

            if (ctx.filter !== 'none') {
                ctx.filter = 'none';
            }

            ctx.globalAlpha = alpha;
        };

        _proto._drawCenterCross = function _drawCenterCross() {
            var cross = this.map.options['centerCross'];

            if (cross) {
                var ctx = this.context;
                var p = new Point(this.canvas.width / 2, this.canvas.height / 2);

                if (isFunction(cross)) {
                    cross(ctx, p);
                } else {
                    Canvas.drawCross(this.context, p.x, p.y, 2, '#f00');
                }
            }
        };

        _proto._drawContainerExtent = function _drawContainerExtent() {
            var cascadePitches = this.map.options.cascadePitches;

            var h30 = this.map.height - this.map._getVisualHeight(cascadePitches[0]);

            var h60 = this.map.height - this.map._getVisualHeight(cascadePitches[1]);

            var extent = this.map.getContainerExtent();
            var ctx = this.context;
            ctx.beginPath();
            ctx.moveTo(0, extent.ymin);
            ctx.lineTo(extent.xmax, extent.ymin);
            ctx.stroke();
            ctx.beginPath();
            ctx.moveTo(0, h30);
            ctx.lineTo(extent.xmax, h30);
            ctx.stroke();
            ctx.beginPath();
            ctx.moveTo(0, h60);
            ctx.lineTo(extent.xmax, h60);
            ctx.stroke();
        };

        _proto._drawFog = function _drawFog() {
            var map = this.map;

            if (map.getPitch() <= map.options['maxVisualPitch'] || !map.options['fog']) {
                return;
            }

            var fogThickness = 30;
            var r = map.getDevicePixelRatio();
            var ctx = this.context,
                clipExtent = map.getContainerExtent();
            var top = (map.height - map._getVisualHeight(75)) * r;
            if (top < 0) top = 0;
            var bottom = clipExtent.ymin * r,
                h = Math.ceil(bottom - top),
                color = map.options['fogColor'].join();
            var gradient = ctx.createLinearGradient(0, top, 0, bottom + fogThickness);
            var landscape = 1 - fogThickness / (h + fogThickness);
            gradient.addColorStop(0, "rgba(" + color + ", 0)");
            gradient.addColorStop(0.3, "rgba(" + color + ", 0.3)");
            gradient.addColorStop(landscape, "rgba(" + color + ", 1)");
            gradient.addColorStop(1, "rgba(" + color + ", 0)");
            ctx.beginPath();
            ctx.fillStyle = gradient;
            ctx.fillRect(0, top, Math.ceil(clipExtent.getWidth()) * r, Math.ceil(h + fogThickness));
        };

        _proto._getAllLayerToRender = function _getAllLayerToRender() {
            return this.map._getLayers();
        };

        _proto.clearCanvas = function clearCanvas() {
            if (!this.canvas) {
                return;
            }

            Canvas.clearRect(this.context, 0, 0, this.canvas.width, this.canvas.height);
        };

        _proto._updateCanvasSize = function _updateCanvasSize() {
            if (!this.canvas || this._containerIsCanvas) {
                return false;
            }

            var map = this.map,
                mapSize = map.getSize(),
                canvas = this.canvas,
                r = map.getDevicePixelRatio();

            if (mapSize['width'] * r === canvas.width && mapSize['height'] * r === canvas.height) {
                return false;
            }

            canvas.height = r * mapSize['height'];
            canvas.width = r * mapSize['width'];

            if (canvas.style) {
                canvas.style.width = mapSize['width'] + 'px';
                canvas.style.height = mapSize['height'] + 'px';
            }

            return true;
        };

        _proto.createCanvas = function createCanvas() {
            if (this._containerIsCanvas) {
                this.canvas = this.map._containerDOM;
            } else {
                this.canvas = createEl('canvas');

                this._updateCanvasSize();

                this.map._panels.canvasContainer.appendChild(this.canvas);
            }

            this.context = this.canvas.getContext('2d');
        };

        _proto._checkSize = function _checkSize() {
            if (!this.map || this.map.isInteracting()) {
                return;
            }

            computeDomPosition(this.map._containerDOM);
            this.map.checkSize();
        };

        _proto._setCheckSizeInterval = function _setCheckSizeInterval(interval) {
            var _this3 = this;

            clearInterval(this._resizeInterval);
            this._checkSizeInterval = interval;
            this._resizeInterval = setInterval(function() {
                if (!_this3.map || _this3.map.isRemoved()) {
                    clearInterval(_this3._resizeInterval);
                } else {
                    _this3._checkSize();
                }
            }, this._checkSizeInterval);
        };

        _proto._registerEvents = function _registerEvents() {
            var _this4 = this;

            var map = this.map;

            if (map.options['checkSize'] && !IS_NODE && typeof window !== 'undefined') {
                this._setCheckSizeInterval(map.options['checkSizeInterval']);
            }

            if (!Browser$1.mobile) {
                map.on('_mousemove', this._onMapMouseMove, this);
            }

            map.on('_dragrotatestart _dragrotating _dragrotateend _movestart _moving _moveend _zoomstart', function(param) {
                _this4._eventParam = param;
            });
            map.on('_zooming', function(param) {
                if (!map.getPitch()) {
                    _this4._zoomMatrix = param['matrix']['container'];
                }

                _this4._eventParam = param;
            });
            map.on('_zoomend', function(param) {
                _this4._eventParam = param;
                delete _this4._zoomMatrix;
            });
            map.on('_spatialreferencechange', function() {
                _this4._spatialRefChanged = true;
            });

            if (Browser$1.webgl && typeof document !== 'undefined') {
                addDomEvent(document, 'visibilitychange', this._thisVisibilitychange, this);
            }
        };

        _proto._onMapMouseMove = function _onMapMouseMove(param) {
            var _this5 = this;

            var map = this.map;

            if (map.isInteracting() || !map.options['hitDetect']) {
                return;
            }

            if (this._hitDetectFrame) {
                cancelAnimFrame(this._hitDetectFrame);
            }

            this._hitDetectFrame = requestAnimFrame(function() {
                _this5.hitDetect(param['containerPoint']);
            });
        };

        _proto._getCanvasLayers = function _getCanvasLayers() {
            return this.map._getLayers(function(layer) {
                return layer.isCanvasRender();
            });
        };

        _proto._onVisibilitychange = function _onVisibilitychange() {
            if (document.visibilityState !== 'visible') {
                return;
            }

            this.setToRedraw();
        };

        return MapCanvasRenderer;
    }(MapRenderer);

    Map$1.registerRenderer('canvas', MapCanvasRenderer);
    Map$1.mergeOptions({
        'fog': false,
        'fogColor': [233, 233, 233]
    });



    var index$6 = /*#__PURE__*/ Object.freeze({
        ResourceCache: ResourceCache,
        CanvasRenderer: CanvasRenderer,
        ImageGLRenderable: ImageGLRenderable,
        MapRenderer: MapRenderer,
        MapCanvasRenderer: MapCanvasRenderer,
        Renderable: Renderable,
        ImageLayerCanvasRenderer: ImageLayerCanvasRenderer,
        ImageLayerGLRenderer: ImageLayerGLRenderer,
        TileLayerCanvasRenderer: TileLayerCanvasRenderer,
        TileLayerGLRenderer: TileLayerGLRenderer,
        CanvasTileLayerCanvasRenderer: CanvasRenderer$1,
        CanvasTileLayerGLRenderer: GLRenderer,
        OverlayLayerCanvasRenderer: OverlayLayerRenderer,
        VectorLayerCanvasRenderer: VectorLayerRenderer,
        CanvasLayerRenderer: CanvasLayerRenderer
    });

    var CenterPointRenderer = {
        _getRenderPoints: function _getRenderPoints() {
            return [
                [this._getCenter2DPoint(this.getMap().getGLZoom())], null
            ];
        }
    };
    Marker.include(CenterPointRenderer);
    Ellipse.include(CenterPointRenderer);
    Circle.include(CenterPointRenderer);
    Sector.include(CenterPointRenderer);
    Rectangle.include({
        _getRenderPoints: function _getRenderPoints(placement) {
            var map = this.getMap();

            if (placement === 'vertex') {
                var shell = this._trimRing(this.getShell());

                var points = [];

                for (var i = 0, len = shell.length; i < len; i++) {
                    points.push(map.coordToPoint(shell[i], map.getGLZoom()));
                }

                return [points, null];
            } else {
                var c = map.coordToPoint(this.getCenter(), map.getGLZoom());
                return [
                    [c], null
                ];
            }
        }
    });
    var PolyRenderer = {
        _getRenderPoints: function _getRenderPoints(placement) {
            var map = this.getMap();
            var glZoom = map.getGLZoom();
            var points,
                rotations = null;

            if (placement === 'point') {
                points = this._getPath2DPoints(this._getPrjCoordinates(), false, glZoom);

                if (points && points.length > 0 && Array.isArray(points[0])) {
                    points = points[0].concat(points[1]);
                }
            } else if (placement === 'vertex') {
                points = this._getPath2DPoints(this._getPrjCoordinates(), false, glZoom);
                rotations = [];

                if (points && points.length > 0 && Array.isArray(points[0])) {
                    for (var i = 0, l = points.length; i < l; i++) {
                        for (var ii = 0, ll = points[i].length; ii < ll; ii++) {
                            if (ii === 0) {
                                rotations.push([points[i][ii], points[i][ii + 1]]);
                            } else {
                                rotations.push([points[i][ii - 1], points[i][ii]]);
                            }
                        }
                    }

                    points = points[0].concat(points[1]);
                } else {
                    for (var _i = 0, _l = points.length; _i < _l; _i++) {
                        if (_i === 0) {
                            rotations.push([points[_i], points[_i + 1]]);
                        } else {
                            rotations.push([points[_i - 1], points[_i]]);
                        }
                    }
                }
            } else if (placement === 'line') {
                points = [];
                rotations = [];

                var vertice = this._getPath2DPoints(this._getPrjCoordinates(), false, glZoom),
                    isSplitted = vertice.length > 0 && Array.isArray(vertice[0]);

                if (isSplitted) {
                    var ring;

                    for (var _i2 = 1, _l2 = vertice.length; _i2 < _l2; _i2++) {
                        ring = vertice[_i2];

                        if (this instanceof Polygon && ring.length > 0 && !ring[0].equals(ring[ring.length - 1])) {
                            ring.push(ring[0]);
                        }

                        for (var _ii = 1, _ll = ring.length; _ii < _ll; _ii++) {
                            points.push(ring[_ii].add(ring[_ii - 1])._multi(0.5));
                            rotations.push([ring[_ii - 1], ring[_ii]]);
                        }
                    }
                } else {
                    if (this instanceof Polygon && vertice.length > 0 && !vertice[0].equals(vertice[vertice.length - 1])) {
                        vertice.push(vertice[0]);
                    }

                    for (var _i3 = 1, _l3 = vertice.length; _i3 < _l3; _i3++) {
                        points.push(vertice[_i3].add(vertice[_i3 - 1])._multi(0.5));
                        rotations.push([vertice[_i3 - 1], vertice[_i3]]);
                    }
                }
            } else if (placement === 'vertex-first') {
                var coords = this._getPrjCoordinates();

                points = coords.length ? [map._prjToPoint(coords[0], glZoom)] : [];
                rotations = coords.length ? [
                    [map._prjToPoint(coords[0], glZoom), map._prjToPoint(coords[1], glZoom)]
                ] : [];
            } else if (placement === 'vertex-last') {
                var _coords = this._getPrjCoordinates();

                var _l4 = _coords.length;
                points = _l4 ? [map._prjToPoint(_coords[_l4 - 1], glZoom)] : [];
                var current = _l4 - 1,
                    previous = _l4 > 1 ? _l4 - 2 : _l4 - 1;
                rotations = _l4 ? [
                    [map._prjToPoint(_coords[previous], glZoom), map._prjToPoint(_coords[current], glZoom)]
                ] : [];
            } else {
                var pcenter = this._getProjection().project(this.getCenter());

                points = [map._prjToPoint(pcenter, glZoom)];
            }

            return [points, rotations];
        }
    };
    LineString.include(PolyRenderer);
    Polygon.include(PolyRenderer);

    Geometry.include({
        _redrawWhenPitch: function _redrawWhenPitch() {
            return false;
        },
        _redrawWhenRotate: function _redrawWhenRotate() {
            return false;
        }
    });
    var el = {
        _redrawWhenPitch: function _redrawWhenPitch() {
            return true;
        },
        _redrawWhenRotate: function _redrawWhenRotate() {
            return this instanceof Ellipse || this instanceof Sector;
        },
        _paintAsPath: function _paintAsPath() {
            var map = this.getMap();
            var altitude = this.getAltitude();
            return altitude > 0 || map.getPitch() || this instanceof Ellipse && map.getBearing();
        },
        _getPaintParams: function _getPaintParams() {
            var map = this.getMap();

            if (this._paintAsPath()) {
                return Polygon.prototype._getPaintParams.call(this, true);
            }

            var pcenter = this._getPrjCoordinates();

            var pt = map._prjToPoint(pcenter, map.getGLZoom());

            var size = this._getRenderSize(pt);

            return [pt].concat(size);
        },
        _paintOn: function _paintOn() {
            if (this._paintAsPath()) {
                return Canvas.polygon.apply(Canvas, arguments);
            } else {
                return Canvas.ellipse.apply(Canvas, arguments);
            }
        },
        _getRenderSize: function _getRenderSize(pt) {
            var map = this.getMap(),
                z = map.getGLZoom();

            var prjExtent = this._getPrjExtent();

            var pmin = map._prjToPoint(prjExtent.getMin(), z),
                pmax = map._prjToPoint(prjExtent.getMax(), z);

            return [Math.abs(pmax.x - pmin.x) / 2, Math.abs(pmax.y - pt.y), Math.abs(pt.y - pmin.y)];
        }
    };
    Ellipse.include(el);
    Circle.include(el);
    Rectangle.include({
        _getPaintParams: function _getPaintParams() {
            var map = this.getMap();
            var pointZoom = map.getGLZoom();

            var shell = this._getPrjShell();

            var points = this._getPath2DPoints(shell, false, pointZoom);

            return [points];
        },
        _paintOn: Canvas.polygon
    });
    Sector.include(el, {
        _redrawWhenPitch: function _redrawWhenPitch() {
            return true;
        },
        _getPaintParams: function _getPaintParams() {
            if (this._paintAsPath()) {
                return Polygon.prototype._getPaintParams.call(this, true);
            }

            var map = this.getMap();

            var pt = map._prjToPoint(this._getPrjCoordinates(), map.getGLZoom());

            var size = this._getRenderSize(pt);

            return [pt, size[0],
                [this.getStartAngle(), this.getEndAngle()]
            ];
        },
        _paintOn: function _paintOn() {
            if (this._paintAsPath()) {
                return Canvas.polygon.apply(Canvas, arguments);
            } else {
                var r = this.getMap().getBearing();
                var args = arguments;

                if (r) {
                    args[3] = args[3].slice(0);
                    args[3][0] += r;
                    args[3][1] += r;
                }

                return Canvas.sector.apply(Canvas, args);
            }
        }
    });
    Path.include({
        _paintAsPath: function _paintAsPath() {
            return true;
        }
    });
    LineString.include({
        arrowStyles: {
            'classic': [3, 4]
        },
        _getArrowShape: function _getArrowShape(prePoint, point, lineWidth, arrowStyle, tolerance) {
            if (!prePoint || !point || prePoint.equals(point)) {
                return null;
            }

            if (!tolerance) {
                tolerance = 0;
            }

            var width = lineWidth * arrowStyle[0],
                height = lineWidth * arrowStyle[1] + tolerance,
                hw = width / 2 + tolerance;
            var normal;

            if (point.nextCtrlPoint || point.prevCtrlPoint) {
                if (point.prevCtrlPoint) {
                    normal = point.sub(new Point(point.prevCtrlPoint));
                } else {
                    normal = point.sub(new Point(point.nextCtrlPoint));
                }
            } else {
                normal = point.sub(prePoint);
            }

            normal._unit();

            var p1 = point.sub(normal.multi(height));

            normal._perp();

            var p0 = p1.add(normal.multi(hw));

            normal._multi(-1);

            var p2 = p1.add(normal.multi(hw));
            return [p0, point, p2, p0];
        },
        _getPaintParams: function _getPaintParams() {
            var prjVertexes = this._getPrjCoordinates();

            var points = this._getPath2DPoints(prjVertexes, false, this.getMap().getGLZoom());

            return [points];
        },
        _paintOn: function _paintOn(ctx, points, lineOpacity, fillOpacity, dasharray) {
            if (this.options['smoothness']) {
                Canvas.paintSmoothLine(ctx, points, lineOpacity, this.options['smoothness'], false, this._animIdx, this._animTailRatio);
            } else {
                Canvas.path(ctx, points, lineOpacity, null, dasharray);
            }

            this._paintArrow(ctx, points, lineOpacity);
        },
        _getArrowPlacement: function _getArrowPlacement() {
            return this.options['arrowPlacement'];
        },
        _getArrowStyle: function _getArrowStyle() {
            var arrowStyle = this.options['arrowStyle'];

            if (arrowStyle) {
                return Array.isArray(arrowStyle) ? arrowStyle : this.arrowStyles[arrowStyle];
            }

            return null;
        },
        _getArrows: function _getArrows(points, lineWidth, tolerance) {
            var arrowStyle = this._getArrowStyle();

            if (!arrowStyle || points.length < 2) {
                return [];
            }

            var isSplitted = points.length > 0 && Array.isArray(points[0]);
            var segments = isSplitted ? points : [points];

            var placement = this._getArrowPlacement();

            var arrows = [];
            var map = this.getMap(),
                first = map.coordToContainerPoint(this.getFirstCoordinate()),
                last = map.coordToContainerPoint(this.getLastCoordinate());

            for (var i = segments.length - 1; i >= 0; i--) {
                if (placement === 'vertex-first' || placement === 'vertex-firstlast' && segments[i][0].closeTo(first, 0.01)) {
                    var arrow = this._getArrowShape(segments[i][1], segments[i][0], lineWidth, arrowStyle, tolerance);

                    if (arrow) {
                        arrows.push(arrow);
                    }
                }

                if (placement === 'vertex-last' || placement === 'vertex-firstlast' && segments[i][segments[i].length - 1].closeTo(last, 0.01)) {
                    var _arrow = this._getArrowShape(segments[i][segments[i].length - 2], segments[i][segments[i].length - 1], lineWidth, arrowStyle, tolerance);

                    if (_arrow) {
                        arrows.push(_arrow);
                    }
                } else if (placement === 'point') {
                    this._getArrowPoints(arrows, segments[i], lineWidth, arrowStyle, tolerance);
                }
            }

            return arrows;
        },
        _getArrowPoints: function _getArrowPoints(arrows, segments, lineWidth, arrowStyle, tolerance) {
            for (var ii = 0, ll = segments.length - 1; ii < ll; ii++) {
                var arrow = this._getArrowShape(segments[ii], segments[ii + 1], lineWidth, arrowStyle, tolerance);

                if (arrow) {
                    arrows.push(arrow);
                }
            }
        },
        _paintArrow: function _paintArrow(ctx, points, lineOpacity) {
            var lineWidth = this._getInternalSymbol()['lineWidth'];

            if (!isNumber(lineWidth) || lineWidth < 3) {
                lineWidth = 3;
            }

            var arrows = this._getArrows(points, lineWidth);

            if (!arrows.length) {
                return;
            }

            if (ctx.setLineDash) {
                ctx.setLineDash([]);
            }

            for (var i = arrows.length - 1; i >= 0; i--) {
                ctx.fillStyle = ctx.strokeStyle;
                Canvas.polygon(ctx, arrows[i], lineOpacity, lineOpacity);
            }
        }
    });
    Polygon.include({
        _getPaintParams: function _getPaintParams(disableSimplify) {
            var maxZoom = this.getMap().getGLZoom();

            var prjVertexes = this._getPrjShell();

            var points = this._getPath2DPoints(prjVertexes, disableSimplify, maxZoom);

            var isSplitted = points.length > 0 && Array.isArray(points[0]);

            if (isSplitted) {
                points = [
                    [points[0]],
                    [points[1]]
                ];
            }

            var prjHoles = this._getPrjHoles();

            var holePoints = [];

            if (prjHoles && prjHoles.length > 0) {
                var simplified = this._simplified;

                for (var i = 0; i < prjHoles.length; i++) {
                    var hole = this._getPath2DPoints(prjHoles[i], disableSimplify, maxZoom);

                    if (Array.isArray(hole) && isSplitted) {
                        if (Array.isArray(hole[0])) {
                            points[0].push(hole[0]);
                            points[1].push(hole[1]);
                        } else {
                            points[0].push(hole);
                        }
                    } else {
                        holePoints.push(hole);
                    }
                }

                if (simplified) {
                    this._simplified = simplified;
                }
            }

            if (!isSplitted) {
                points = [points];
                pushIn(points, holePoints);
            }

            return [points];
        },
        _paintOn: function _paintOn(ctx, points, lineOpacity, fillOpacity, dasharray) {
            Canvas.polygon(ctx, points, lineOpacity, fillOpacity, dasharray, this.options['smoothness']);
        }
    });

    Map$1.VERSION = version;

    exports.Util = index$1;
    exports.DomUtil = dom;
    exports.StringUtil = strings;
    exports.MapboxUtil = index;
    exports.Map = Map$1;
    exports.ui = index$4;
    exports.control = index$5;
    exports.renderer = index$6;
    exports.symbolizer = index$3;
    exports.animation = Animation$1;
    exports.Browser = Browser$1;
    exports.Ajax = Ajax;
    exports.Canvas = Canvas;
    exports.Promise = Promise$1;
    exports.Class = Class;
    exports.Eventable = Eventable;
    exports.JSONAble = JSONAble;
    exports.Handlerable = Handlerable;
    exports.Handler = Handler$1;
    exports.DragHandler = DragHandler;
    exports.MapTool = MapTool;
    exports.DrawTool = DrawTool;
    exports.AreaTool = AreaTool;
    exports.DistanceTool = DistanceTool;
    exports.SpatialReference = SpatialReference;
    exports.INTERNAL_LAYER_PREFIX = INTERNAL_LAYER_PREFIX;
    exports.GEOMETRY_COLLECTION_TYPES = GEOMETRY_COLLECTION_TYPES;
    exports.GEOJSON_TYPES = GEOJSON_TYPES;
    exports.RESOURCE_PROPERTIES = RESOURCE_PROPERTIES;
    exports.RESOURCE_SIZE_PROPERTIES = RESOURCE_SIZE_PROPERTIES;
    exports.NUMERICAL_PROPERTIES = NUMERICAL_PROPERTIES;
    exports.COLOR_PROPERTIES = COLOR_PROPERTIES;
    exports.DEFAULT_TEXT_SIZE = DEFAULT_TEXT_SIZE;
    exports.projection = projections;
    exports.measurer = index$2;
    exports.Coordinate = Coordinate;
    exports.CRS = CRS;
    exports.Extent = Extent;
    exports.Point = Point;
    exports.PointExtent = PointExtent;
    exports.Size = Size;
    exports.Transformation = Transformation;
    exports.Layer = Layer;
    exports.TileLayer = TileLayer;
    exports.GroupTileLayer = GroupTileLayer;
    exports.WMSTileLayer = WMSTileLayer;
    exports.CanvasTileLayer = CanvasTileLayer;
    exports.ImageLayer = ImageLayer;
    exports.OverlayLayer = OverlayLayer;
    exports.VectorLayer = VectorLayer;
    exports.CanvasLayer = CanvasLayer;
    exports.ParticleLayer = ParticleLayer;
    exports.TileSystem = TileSystem;
    exports.TileConfig = TileConfig;
    exports.ArcCurve = ArcCurve;
    exports.Circle = Circle;
    exports.ConnectorLine = ConnectorLine;
    exports.ArcConnectorLine = ArcConnectorLine;
    exports.CubicBezierCurve = CubicBezierCurve;
    exports.Curve = Curve;
    exports.Ellipse = Ellipse;
    exports.GeoJSON = GeoJSON;
    exports.Geometry = Geometry;
    exports.GeometryCollection = GeometryCollection;
    exports.Label = Label;
    exports.LineString = LineString;
    exports.Marker = Marker;
    exports.MultiLineString = MultiLineString;
    exports.MultiPoint = MultiPoint;
    exports.MultiPolygon = MultiPolygon;
    exports.Polygon = Polygon;
    exports.QuadBezierCurve = QuadBezierCurve;
    exports.Rectangle = Rectangle;
    exports.Sector = Sector;
    exports.TextBox = TextBox;
    exports.TextMarker = TextMarker;

    Object.defineProperty(exports, '__esModule', { value: true });

    typeof console !== 'undefined' && console.log && console.log('maptalks v0.49.5');

})));