/*!
 * maptalks v1.0.0-alpha.15
 * LICENSE : BSD-3-Clause
 * (c) 2016-2021 maptalks.org
 */
var version = "1.0.0-alpha.15";

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;
        };

        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,
    parseSymbolPath: parseSymbolPath
});

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;
    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.mag = function mag() {
        return Math.sqrt(this.x * this.x + this.y * this.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 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 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;
    },
    pixelRect: function pixelRect(ctx, point, lineOpacity, fillOpacity) {
        var lineWidth = ctx.lineWidth;
        var alpha = ctx.globalAlpha;

        if (lineWidth > 0 && lineOpacity > 0) {
            if (ctx.fillStyle !== ctx.strokeStyle) {
                ctx.fillStyle = ctx.strokeStyle;
            }

            if (lineOpacity < 1) {
                ctx.globalAlpha *= lineOpacity;
            }
        } else if (fillOpacity > 0) {
            if (fillOpacity < 1) {
                ctx.globalAlpha *= fillOpacity;
            }
        } else {
            return;
        }

        ctx.canvas._drawn = true;
        ctx.fillRect(point[0], point[1], 1, 1);

        if (ctx.globalAlpha !== alpha) {
            ctx.globalAlpha = alpha;
        }
    }
};

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);
});

var quickselect = createCommonjsModule(function(module, exports) {
    (function(global, factory) {
        module.exports = factory();
    })(commonjsGlobal, function() {

        function quickselect(arr, k, left, right, compare) {
            quickselectStep(arr, k, left || 0, right || arr.length - 1, compare || defaultCompare);
        }

        function quickselectStep(arr, k, left, right, compare) {
            while (right > left) {
                if (right - left > 600) {
                    var n = right - left + 1;
                    var m = k - left + 1;
                    var z = Math.log(n);
                    var s = 0.5 * Math.exp(2 * z / 3);
                    var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
                    var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
                    var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
                    quickselectStep(arr, k, newLeft, newRight, compare);
                }

                var t = arr[k];
                var i = left;
                var j = right;
                swap(arr, left, k);
                if (compare(arr[right], t) > 0) swap(arr, left, right);

                while (i < j) {
                    swap(arr, i, j);
                    i++;
                    j--;

                    while (compare(arr[i], t) < 0) {
                        i++;
                    }

                    while (compare(arr[j], t) > 0) {
                        j--;
                    }
                }

                if (compare(arr[left], t) === 0) swap(arr, left, j);
                else {
                    j++;
                    swap(arr, j, right);
                }
                if (j <= k) left = j + 1;
                if (k <= j) right = j - 1;
            }
        }

        function swap(arr, i, j) {
            var tmp = arr[i];
            arr[i] = arr[j];
            arr[j] = tmp;
        }

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

        return quickselect;
    });
});

var rbush_1 = rbush;
var default_1 = rbush;

function rbush(maxEntries, format) {
    if (!(this instanceof rbush)) return new rbush(maxEntries, format);
    this._maxEntries = Math.max(4, maxEntries || 9);
    this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));

    if (format) {
        this._initFormat(format);
    }

    this.clear();
}

rbush.prototype = {
    all: function all() {
        return this._all(this.data, []);
    },
    search: function search(bbox) {
        var node = this.data,
            result = [],
            toBBox = this.toBBox;
        if (!intersects(bbox, node)) return result;
        var nodesToSearch = [],
            i,
            len,
            child,
            childBBox;

        while (node) {
            for (i = 0, len = node.children.length; i < len; i++) {
                child = node.children[i];
                childBBox = node.leaf ? toBBox(child) : child;

                if (intersects(bbox, childBBox)) {
                    if (node.leaf) result.push(child);
                    else if (contains(bbox, childBBox)) this._all(child, result);
                    else nodesToSearch.push(child);
                }
            }

            node = nodesToSearch.pop();
        }

        return result;
    },
    collides: function collides(bbox) {
        var node = this.data,
            toBBox = this.toBBox;
        if (!intersects(bbox, node)) return false;
        var nodesToSearch = [],
            i,
            len,
            child,
            childBBox;

        while (node) {
            for (i = 0, len = node.children.length; i < len; i++) {
                child = node.children[i];
                childBBox = node.leaf ? toBBox(child) : child;

                if (intersects(bbox, childBBox)) {
                    if (node.leaf || contains(bbox, childBBox)) return true;
                    nodesToSearch.push(child);
                }
            }

            node = nodesToSearch.pop();
        }

        return false;
    },
    load: function load(data) {
        if (!(data && data.length)) return this;

        if (data.length < this._minEntries) {
            for (var i = 0, len = data.length; i < len; i++) {
                this.insert(data[i]);
            }

            return this;
        }

        var node = this._build(data.slice(), 0, data.length - 1, 0);

        if (!this.data.children.length) {
            this.data = node;
        } else if (this.data.height === node.height) {
            this._splitRoot(this.data, node);
        } else {
            if (this.data.height < node.height) {
                var tmpNode = this.data;
                this.data = node;
                node = tmpNode;
            }

            this._insert(node, this.data.height - node.height - 1, true);
        }

        return this;
    },
    insert: function insert(item) {
        if (item) this._insert(item, this.data.height - 1);
        return this;
    },
    clear: function clear() {
        this.data = createNode([]);
        return this;
    },
    remove: function remove(item, equalsFn) {
        if (!item) return this;
        var node = this.data,
            bbox = this.toBBox(item),
            path = [],
            indexes = [],
            i,
            parent,
            index,
            goingUp;

        while (node || path.length) {
            if (!node) {
                node = path.pop();
                parent = path[path.length - 1];
                i = indexes.pop();
                goingUp = true;
            }

            if (node.leaf) {
                index = findItem(item, node.children, equalsFn);

                if (index !== -1) {
                    node.children.splice(index, 1);
                    path.push(node);

                    this._condense(path);

                    return this;
                }
            }

            if (!goingUp && !node.leaf && contains(node, bbox)) {
                path.push(node);
                indexes.push(i);
                i = 0;
                parent = node;
                node = node.children[0];
            } else if (parent) {
                i++;
                node = parent.children[i];
                goingUp = false;
            } else node = null;
        }

        return this;
    },
    toBBox: function toBBox(item) {
        return item;
    },
    compareMinX: compareNodeMinX,
    compareMinY: compareNodeMinY,
    toJSON: function toJSON() {
        return this.data;
    },
    fromJSON: function fromJSON(data) {
        this.data = data;
        return this;
    },
    _all: function _all(node, result) {
        var nodesToSearch = [];

        while (node) {
            if (node.leaf) result.push.apply(result, node.children);
            else nodesToSearch.push.apply(nodesToSearch, node.children);
            node = nodesToSearch.pop();
        }

        return result;
    },
    _build: function _build(items, left, right, height) {
        var N = right - left + 1,
            M = this._maxEntries,
            node;

        if (N <= M) {
            node = createNode(items.slice(left, right + 1));
            calcBBox(node, this.toBBox);
            return node;
        }

        if (!height) {
            height = Math.ceil(Math.log(N) / Math.log(M));
            M = Math.ceil(N / Math.pow(M, height - 1));
        }

        node = createNode([]);
        node.leaf = false;
        node.height = height;
        var N2 = Math.ceil(N / M),
            N1 = N2 * Math.ceil(Math.sqrt(M)),
            i,
            j,
            right2,
            right3;
        multiSelect(items, left, right, N1, this.compareMinX);

        for (i = left; i <= right; i += N1) {
            right2 = Math.min(i + N1 - 1, right);
            multiSelect(items, i, right2, N2, this.compareMinY);

            for (j = i; j <= right2; j += N2) {
                right3 = Math.min(j + N2 - 1, right2);
                node.children.push(this._build(items, j, right3, height - 1));
            }
        }

        calcBBox(node, this.toBBox);
        return node;
    },
    _chooseSubtree: function _chooseSubtree(bbox, node, level, path) {
        var i, len, child, targetNode, area, enlargement, minArea, minEnlargement;

        while (true) {
            path.push(node);
            if (node.leaf || path.length - 1 === level) break;
            minArea = minEnlargement = Infinity;

            for (i = 0, len = node.children.length; i < len; i++) {
                child = node.children[i];
                area = bboxArea(child);
                enlargement = enlargedArea(bbox, child) - area;

                if (enlargement < minEnlargement) {
                    minEnlargement = enlargement;
                    minArea = area < minArea ? area : minArea;
                    targetNode = child;
                } else if (enlargement === minEnlargement) {
                    if (area < minArea) {
                        minArea = area;
                        targetNode = child;
                    }
                }
            }

            node = targetNode || node.children[0];
        }

        return node;
    },
    _insert: function _insert(item, level, isNode) {
        var toBBox = this.toBBox,
            bbox = isNode ? item : toBBox(item),
            insertPath = [];

        var node = this._chooseSubtree(bbox, this.data, level, insertPath);

        node.children.push(item);
        extend$2(node, bbox);

        while (level >= 0) {
            if (insertPath[level].children.length > this._maxEntries) {
                this._split(insertPath, level);

                level--;
            } else break;
        }

        this._adjustParentBBoxes(bbox, insertPath, level);
    },
    _split: function _split(insertPath, level) {
        var node = insertPath[level],
            M = node.children.length,
            m = this._minEntries;

        this._chooseSplitAxis(node, m, M);

        var splitIndex = this._chooseSplitIndex(node, m, M);

        var newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));
        newNode.height = node.height;
        newNode.leaf = node.leaf;
        calcBBox(node, this.toBBox);
        calcBBox(newNode, this.toBBox);
        if (level) insertPath[level - 1].children.push(newNode);
        else this._splitRoot(node, newNode);
    },
    _splitRoot: function _splitRoot(node, newNode) {
        this.data = createNode([node, newNode]);
        this.data.height = node.height + 1;
        this.data.leaf = false;
        calcBBox(this.data, this.toBBox);
    },
    _chooseSplitIndex: function _chooseSplitIndex(node, m, M) {
        var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index;
        minOverlap = minArea = Infinity;

        for (i = m; i <= M - m; i++) {
            bbox1 = distBBox(node, 0, i, this.toBBox);
            bbox2 = distBBox(node, i, M, this.toBBox);
            overlap = intersectionArea(bbox1, bbox2);
            area = bboxArea(bbox1) + bboxArea(bbox2);

            if (overlap < minOverlap) {
                minOverlap = overlap;
                index = i;
                minArea = area < minArea ? area : minArea;
            } else if (overlap === minOverlap) {
                if (area < minArea) {
                    minArea = area;
                    index = i;
                }
            }
        }

        return index;
    },
    _chooseSplitAxis: function _chooseSplitAxis(node, m, M) {
        var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX,
            compareMinY = node.leaf ? this.compareMinY : compareNodeMinY,
            xMargin = this._allDistMargin(node, m, M, compareMinX),
            yMargin = this._allDistMargin(node, m, M, compareMinY);

        if (xMargin < yMargin) node.children.sort(compareMinX);
    },
    _allDistMargin: function _allDistMargin(node, m, M, compare) {
        node.children.sort(compare);
        var toBBox = this.toBBox,
            leftBBox = distBBox(node, 0, m, toBBox),
            rightBBox = distBBox(node, M - m, M, toBBox),
            margin = bboxMargin(leftBBox) + bboxMargin(rightBBox),
            i,
            child;

        for (i = m; i < M - m; i++) {
            child = node.children[i];
            extend$2(leftBBox, node.leaf ? toBBox(child) : child);
            margin += bboxMargin(leftBBox);
        }

        for (i = M - m - 1; i >= m; i--) {
            child = node.children[i];
            extend$2(rightBBox, node.leaf ? toBBox(child) : child);
            margin += bboxMargin(rightBBox);
        }

        return margin;
    },
    _adjustParentBBoxes: function _adjustParentBBoxes(bbox, path, level) {
        for (var i = level; i >= 0; i--) {
            extend$2(path[i], bbox);
        }
    },
    _condense: function _condense(path) {
        for (var i = path.length - 1, siblings; i >= 0; i--) {
            if (path[i].children.length === 0) {
                if (i > 0) {
                    siblings = path[i - 1].children;
                    siblings.splice(siblings.indexOf(path[i]), 1);
                } else this.clear();
            } else calcBBox(path[i], this.toBBox);
        }
    },
    _initFormat: function _initFormat(format) {
        var compareArr = ['return a', ' - b', ';'];
        this.compareMinX = new Function('a', 'b', compareArr.join(format[0]));
        this.compareMinY = new Function('a', 'b', compareArr.join(format[1]));
        this.toBBox = new Function('a', 'return {minX: a' + format[0] + ', minY: a' + format[1] + ', maxX: a' + format[2] + ', maxY: a' + format[3] + '};');
    }
};

function findItem(item, items, equalsFn) {
    if (!equalsFn) return items.indexOf(item);

    for (var i = 0; i < items.length; i++) {
        if (equalsFn(item, items[i])) return i;
    }

    return -1;
}

function calcBBox(node, toBBox) {
    distBBox(node, 0, node.children.length, toBBox, node);
}

function distBBox(node, k, p, toBBox, destNode) {
    if (!destNode) destNode = createNode(null);
    destNode.minX = Infinity;
    destNode.minY = Infinity;
    destNode.maxX = -Infinity;
    destNode.maxY = -Infinity;

    for (var i = k, child; i < p; i++) {
        child = node.children[i];
        extend$2(destNode, node.leaf ? toBBox(child) : child);
    }

    return destNode;
}

function extend$2(a, b) {
    a.minX = Math.min(a.minX, b.minX);
    a.minY = Math.min(a.minY, b.minY);
    a.maxX = Math.max(a.maxX, b.maxX);
    a.maxY = Math.max(a.maxY, b.maxY);
    return a;
}

function compareNodeMinX(a, b) {
    return a.minX - b.minX;
}

function compareNodeMinY(a, b) {
    return a.minY - b.minY;
}

function bboxArea(a) {
    return (a.maxX - a.minX) * (a.maxY - a.minY);
}

function bboxMargin(a) {
    return a.maxX - a.minX + (a.maxY - a.minY);
}

function enlargedArea(a, b) {
    return (Math.max(b.maxX, a.maxX) - Math.min(b.minX, a.minX)) * (Math.max(b.maxY, a.maxY) - Math.min(b.minY, a.minY));
}

function intersectionArea(a, b) {
    var minX = Math.max(a.minX, b.minX),
        minY = Math.max(a.minY, b.minY),
        maxX = Math.min(a.maxX, b.maxX),
        maxY = Math.min(a.maxY, b.maxY);
    return Math.max(0, maxX - minX) * Math.max(0, maxY - minY);
}

function contains(a, b) {
    return a.minX <= b.minX && a.minY <= b.minY && b.maxX <= a.maxX && b.maxY <= a.maxY;
}

function intersects(a, b) {
    return b.minX <= a.maxX && b.minY <= a.maxY && b.maxX >= a.minX && b.maxY >= a.minY;
}

function createNode(children) {
    return {
        children: children,
        height: 1,
        leaf: true,
        minX: Infinity,
        minY: Infinity,
        maxX: -Infinity,
        maxY: -Infinity
    };
}

function multiSelect(arr, left, right, n, compare) {
    var stack = [left, right],
        mid;

    while (stack.length) {
        right = stack.pop();
        left = stack.pop();
        if (right - left <= n) continue;
        mid = left + Math.ceil((right - left) / n / 2) * n;
        quickselect(arr, mid, left, right, compare);
        stack.push(left, mid, mid, right);
    }
}
rbush_1.default = default_1;

var search = {};

var CollisionIndex = function() {
    function CollisionIndex() {
        this._tree = rbush_1(9, ['[0]', '[1]', '[2]', '[3]']);
    }

    var _proto = CollisionIndex.prototype;

    _proto.collides = function collides(box) {
        search.minX = box[0];
        search.minY = box[1];
        search.maxX = box[2];
        search.maxY = box[3];
        return this._tree.collides(search);
    };

    _proto.insertBox = function insertBox(box) {
        var tree = this._tree;
        tree.insert(box);
        return this;
    };

    _proto.bulkInsertBox = function bulkInsertBox(boxes) {
        this._tree.load(boxes);

        return this;
    };

    _proto.clear = function clear() {
        this._tree.clear();

        return this;
    };

    return CollisionIndex;
}();

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'];
        var renderer = this.layer.options['renderer'] || '';
        return function(resolve) {
            if (resources.isResourceLoaded(url, true)) {
                resolve(url);
                return;
            }

            var img = new Image();

            if (!isNil(crossOrigin)) {
                img['crossOrigin'] = crossOrigin;
            } else if (renderer !== 'canvas') {
                img['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 (isFunctionDefinition(this.symbol['opacity'])) {
            if (!this._opacityFn) {
                this._opacityFn = interpolated(this.symbol['opacity']);
            }
        } else {
            delete this._opacityFn;
        }

        if (isNumber(this.symbol['opacity'])) {
            if (ctx.globalAlpha !== this.symbol['opacity']) {
                ctx.globalAlpha = this.symbol['opacity'];
            }
        } else if (this._opacityFn) {
            var map = this.getMap();
            ctx.globalAlpha = this._opacityFn(map.getZoom());
        } 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 TEMP_POINT2 = new Point(0, 0);
var TEMP_POINT3 = 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();

        if (painter.isSpriting()) {
            return this._getRenderPoints()[0];
        }

        var geometry = this.geometry;
        var dxdy = this.getDxDy();
        var cpoints;

        if (geometry._cPoint && !ignoreAltitude) {
            var p = ignoreAltitude ? TEMP_POINT2 : TEMP_POINT3;
            p.set(geometry._cPoint.x, geometry._cPoint.y);
            var containerOffset = painter.containerOffset;

            p._sub(containerOffset);

            var dx = dxdy.x,
                dy = dxdy.y;

            if (dx || dy) {
                p._add(dx || 0, dy || 0);
            }

            cpoints = [p];
        } else {
            var points = this._getRenderPoints()[0];

            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 TEMP_SIZE = new Size(1, 1);

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.getRotation() ? this._rotate(ctx, point, this._getRotationAt(i)) : null;

            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.getRotation() ? this._rotate(ctx, point, this._getRotationAt(i)) : null;

            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;
        TEMP_SIZE.width = w;
        TEMP_SIZE.height = h;
        var p = getAlignPoint(TEMP_SIZE, 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 TEMP_SIZE$1 = new Size(1, 1);

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'];
        }

        TEMP_SIZE$1.width = width;
        TEMP_SIZE$1.height = height;
        var alignPoint = getAlignPoint(TEMP_SIZE$1, style['markerHorizontalAlignment'], style['markerVerticalAlignment']);

        for (var i = 0, len = cookedPoints.length; i < len; i++) {
            var p = cookedPoints[i];
            var origin = this.getRotation() ? this._rotate(ctx, p, this._getRotationAt(i)) : null;

            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();
        TEMP_SIZE$1.width = width;
        TEMP_SIZE$1.height = height;
        var alignPoint = getAlignPoint(TEMP_SIZE$1, 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.getRotation() ? this._rotate(ctx, p, this._getRotationAt(i)) : null;

            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_EXTENT1 = new PointExtent();
var TEMP_BBOX = {
    minx: Infinity,
    miny: Infinity,
    maxx: -Infinity,
    maxy: -Infinity
};

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 renderer = this.getLayer()._getRenderer();

        var mapStateCache = renderer.mapStateCache;
        var resolution, pitch, bearing, glScale, containerExtent;
        var map = this.getMap();

        if (mapStateCache && !this._hitPoint) {
            resolution = mapStateCache.resolution;
            pitch = mapStateCache.pitch;
            bearing = mapStateCache.bearing;
            glScale = mapStateCache.glScale;
            containerExtent = mapStateCache.containerExtent;
        } else {
            resolution = map.getResolution();
            pitch = map.getPitch();
            bearing = map.getBearing();
            glScale = map.getGLScale();
            containerExtent = map.getContainerExtent();
        }

        var geometry = this.geometry,
            res = resolution,
            pitched = pitch !== 0,
            rotated = bearing !== 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 !== resolution || 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 = glScale,
            tr = [],
            points = params[0];
        var mapExtent = containerExtent;

        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 renderer = this.getLayer()._getRenderer();

        var mapStateCache = renderer.mapStateCache;
        var map = this.getMap(),
            containerOffset = this.containerOffset;
        var glZoom;

        if (mapStateCache) {
            glZoom = mapStateCache.glZoom;
        } else {
            glZoom = map.getGLZoom();
        }

        var cPoints;
        var roundPoint = this.getLayer().options['roundPoint'];
        var minx = Infinity,
            miny = Infinity,
            maxx = -Infinity,
            maxy = -Infinity;

        function pointsContainerPoints(viewPoints, alts) {
            if (viewPoints === void 0) {
                viewPoints = [];
            }

            if (alts === void 0) {
                alts = [];
            }

            var pts = map._pointsToContainerPoints(viewPoints, glZoom, alts);

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

                p._sub(containerOffset);

                if (dx || dy) {
                    p._add(dx || 0, dy || 0);
                }

                if (roundPoint) {
                    p.x = Math.ceil(p.x);
                    p.y = Math.ceil(p.y);
                }

                minx = Math.min(p.x, minx);
                miny = Math.min(p.y, miny);
                maxx = Math.max(p.x, maxx);
                maxy = Math.max(p.y, maxy);
            }

            return pts;
        }

        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 = [];
            var alts = [];
            var altitudeIsNumber = isNumber(altitude);

            for (var i = 0, l = clipPoints.length; i < l; i++) {
                var c = clipPoints[i];

                if (Array.isArray(c)) {
                    if (altitudeIsNumber) {
                        var _cring = pointsContainerPoints(c, altitude);

                        cPoints.push(_cring);
                        continue;
                    }

                    var altArray = [];

                    for (var ii = 0, ll = c.length; ii < ll; ii++) {
                        if (Array.isArray(altitude)) {
                            if (altitude[i]) {
                                alt = altitude[i][ii];
                            } else {
                                alt = 0;
                            }
                        }

                        altArray.push(alt);
                    }

                    var cring = pointsContainerPoints(c, altArray);
                    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];
                        }
                    }

                    alts.push(alt);
                }
            }

            if (alts.length) {
                cPoints = pointsContainerPoints(clipPoints, alts);
            }
        } else if (points instanceof Point) {
            if (ignoreAltitude) {
                altitude = 0;
            }

            cPoints = map._pointToContainerPoint(points, glZoom, altitude)._sub(containerOffset);

            if (dx || dy) {
                cPoints._add(dx, dy);
            }
        }

        TEMP_BBOX.minx = minx;
        TEMP_BBOX.miny = miny;
        TEMP_BBOX.maxx = maxx;
        TEMP_BBOX.maxy = maxy;
        this.__bbox = TEMP_BBOX;
        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 renderer = this.getLayer()._getRenderer();

        var mapStateCache = renderer.mapStateCache;

        var _2DExtent, glExtent, pitch;

        if (mapStateCache) {
            _2DExtent = mapStateCache._2DExtent;
            glExtent = mapStateCache.glExtent;
            pitch = mapStateCache.pitch;
        } else {
            _2DExtent = map._get2DExtent();
            glExtent = map._get2DExtent(map.getGLZoom());
            pitch = map.getPitch();
        }

        var extent2D = _2DExtent._expand(lineWidth);

        if (pitch > 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 = glExtent._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;
        }

        var mapStateCache = renderer.mapStateCache || {};

        if (!this.geometry._isCheck) {
            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 || mapStateCache.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;
                }
            }
        } else if (r1 || r2) {
            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();
        this.__symbol = JSON.stringify(this._symbol);
        return this;
    };

    _proto.updateSymbol = function updateSymbol(props) {
        if (!props) {
            return this;
        }

        var s = this._getSymbol();

        if (Array.isArray(s)) {
            if (!Array.isArray(props)) {
                throw new Error('Parameter of updateSymbol is not an array.');
            }

            for (var i = 0; i < props.length; i++) {
                if (s[i] && props[i]) {
                    s[i] = extendSymbol(s[i], props[i]);
                }
            }
        } else if (Array.isArray(props)) {
            throw new Error('Geometry\'s symbol is not an array to update.');
        } else 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']) || isObject(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) {
            if (this._dirtyCoords) {
                delete this._dirtyCoords;

                var projection = this._getProjection();

                if (projection) {
                    this._pcenter = projection.project(this._coordinates);

                    this._clearCache();
                }
            }

            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,
    'collision': false,
    'collisionScope': 'layer',
    '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.getCollisionIndex = function getCollisionIndex() {
        if (this.options['collisionScope'] === 'layer') {
            if (!this._collisionIndex) {
                this._collisionIndex = new CollisionIndex();
            }

            return this._collisionIndex;
        }

        var map = this.getMap();

        if (!map) {
            return null;
        }

        return map.getCollisionIndex();
    };

    _proto.clearCollisionIndex = function clearCollisionIndex() {
        if (this.options['collisionScope'] === 'layer' && this._collisionIndex) {
            this._collisionIndex.clear();
        }

        return this;
    };

    _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;
        delete this._collisionIndex;
    };

    _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);
};

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(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 TEMP_COORD = new Coordinate(0, 0);
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],
    'renderable': true
};

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$$1, fromZoom, isFraction) {
        var zoom = this.getZoom();

        if (isNil(fromZoom)) {
            fromZoom = zoom;
        }

        if (scale$$1 === 1 && fromZoom === zoom) {
            return zoom;
        }

        var res = this._getResolution(fromZoom),
            targetRes = res / scale$$1;

        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.coordToPoint(p);
        });
        var w = containerExtent.getWidth(),
            h = containerExtent.getHeight();
        var scaleX = size['width'] / w,
            scaleY = size['height'] / h;
        var scale$$1 = this.getSpatialReference().getZoomDirection() < 0 ? Math.max(scaleX, scaleY) : Math.min(scaleX, scaleY);
        var zoom = this.getZoomForScale(scale$$1, 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, options.quality || 0.92);

            if (save && dataURL) {
                var imgURL;

                if (typeof Blob !== 'undefined' && typeof atob !== 'undefined') {
                    var blob = b64toBlob(dataURL.replace(/^data:image\/(png|jpeg|jpg|webp);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.isOffscreen = function isOffscreen(box, viewportPadding) {
        if (viewportPadding === void 0) {
            viewportPadding = 0;
        }

        var width = this.width,
            height = this.height;
        var screenRightBoundary = width + viewportPadding;
        var screenBottomBoundary = height + viewportPadding;
        var xmin = box.xmin,
            ymin = box.ymin,
            xmax = box.xmax,
            ymax = box.ymax;

        if (Array.isArray(box)) {
            xmin = box[0];
            ymin = box[1];
            xmax = box[2];
            ymax = box[3];
        }

        return xmax < viewportPadding || xmin >= screenRightBoundary || ymax < viewportPadding || ymin > screenBottomBoundary;
    };

    _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;

            if (this._layers[i].sortLayersByZIndex) {
                this._layers[i].sortLayersByZIndex();
            }
        }

        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._prjsToPoints = function _prjsToPoints(pCoords, zoom) {
        zoom = isNil(zoom) ? this.getZoom() : zoom;

        var res = this._getResolution(zoom);

        var transformation = this._spatialReference.getTransformation();

        var pts = [];

        for (var i = 0, len = pCoords.length; i < len; i++) {
            var pt = transformation.transform(pCoords[i], res);
            pts.push(pt);
        }

        return pts;
    };

    _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);
        };
    }(),
    coordinatesToContainerPoints: function() {
        return function(coordinates, zoom) {
            zoom = isNil(zoom) ? this.getZoom() : zoom;
            var pts = [];

            var transformation = this._spatialReference.getTransformation();

            var resolution = this._getResolution(zoom);

            var res = resolution / this._getResolution();

            var projection = this.getProjection();
            var tempOut = [0, 0, 0];
            var prjOut = new Coordinate(0, 0);
            var isTransforming = this.isTransforming();

            var centerPoint = this._prjToPoint(this._getPrjCenter(), undefined, TEMP_COORD);

            var w = this.width / 2,
                h = this.height / 2;

            for (var i = 0, len = coordinates.length; i < len; i++) {
                var pCoordinate = projection.project(coordinates[i], prjOut);
                var point = transformation.transform(pCoordinate, resolution);
                point = point._multi(res);

                if (isTransforming) {
                    var scale$$1 = this._glScale;
                    set$2(tempOut, point.x * scale$$1, point.y * scale$$1, 0);

                    var t = this._projIfBehindCamera(tempOut, this.cameraPosition, this.cameraForward);

                    applyMatrix(t, t, this.projViewMatrix);
                    var w2 = w,
                        h2 = h;
                    t[0] = t[0] * w2 + w2;
                    t[1] = -(t[1] * h2) + h2;
                    point.x = t[0];
                    point.y = t[1];
                    pts.push(point);
                } else {
                    var out = point;

                    out._sub(centerPoint.x, centerPoint.y);

                    out.set(out.x, -out.y);
                    pts.push(out._add(w, h));
                }
            }

            return pts;
        };
    }(),
    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$$1 = 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$$1)._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 && 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': true
});
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();
        }

        if (!Array.isArray(prjCoords)) {
            return map._prjToPoint(prjCoords, zoom);
        } else {
            if (!Array.isArray(prjCoords[0])) {
                return map._prjsToPoints(prjCoords, zoom);
            }

            var pts = [];

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

                var pt = map._prjsToPoints(prjCoord, zoom);

                pts.push(pt);
            }

            return pts;
        }
    };

    _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._dirtyCoords = true;
                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;
        }

        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,
    'sortByDistanceToCamera': false,
    'roundPoint': 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 touchmove': _this._mouseMoveHandler,
            'dblclick': _this._doubleClickHandler,
            'mousedown touchstart': _this._mouseDownHandler,
            'mouseup touchend': _this._mouseUpHandler,
            'mousemove': _this._mouseMoveHandler,
            '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'];

        var dragging = false;

        for (var i = 0; i < actions.length; i++) {
            if (actions[i].indexOf('mousemove') >= 0) {
                dragging = true;
                break;
            }
        }

        if (dragging) {
            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._clickCoords && this._clickCoords.length) {
            var len = this._clickCoords.length;

            var prjCoord = this.getMap()._pointToPrj(event['point2d']);

            if (this._clickCoords[len - 1].equals(prjCoord)) {
                return;
            }
        }

        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);

            if (this._clickCoords.length <= 1) {
                this._fireEvent('drawstart', event);
            } else {
                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 mode = this.getMode();

        if (mode && mode.indexOf('polygon') > -1 && clickCoords.length < 3) {
            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[0].indexOf('mousedown') >= 0 || action[0].indexOf('touchstart') >= 0) {
            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;
    },
    flyTo: function flyTo(view, options, step) {
        var _this2 = this;

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

        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);
            }
        }

        if (isFunction(options)) {
            step = options;
            options = {};
        }

        options = extend({
            curve: 1.42
        }, options);
        var map = this;

        function zoomScale(z0, z1) {
            return map.getResolution(z1) / map.getResolution(z0);
        }

        var zoomOrigin = view['around'] || new Point(this.width / 2, this.height / 2);
        var minZoom = this.getMinZoom();
        var maxZoom = this.getMaxZoom();
        var projection = this.getProjection();
        var currView = this.getView();
        var startZoom = currView.zoom;
        var startBearing = currView.bearing;
        var startPitch = currView.pitch;
        var zoom = 'zoom' in view ? clamp(+view.zoom, minZoom, maxZoom) : startZoom;
        var bearing = 'bearing' in view ? +view.bearing : startBearing;
        var pitch = 'pitch' in view ? +view.pitch : startPitch;
        var center = projection.project(view.center && new Coordinate(view.center) || this.getCenter());
        var scale = zoomScale(zoom, startZoom);
        var from = projection.project(this.getCenter());
        var delta = center.sub(from);
        var rho = options.curve;
        var w0 = Math.max(this.width, this.height),
            w1 = w0 / scale,
            u1 = delta.mag();

        if ('minZoom' in options) {
            var animMinZoom = clamp(Math.min(options.minZoom, startZoom, zoom), minZoom, maxZoom);
            var wMax = w0 / zoomScale(animMinZoom, startZoom);
            rho = Math.sqrt(wMax / u1 * 2);
        }

        var rho2 = rho * rho;

        function r(i) {
            var b = (w1 * w1 - w0 * w0 + (i ? -1 : 1) * rho2 * rho2 * u1 * u1) / (2 * (i ? w1 : w0) * rho2 * u1);
            return Math.log(Math.sqrt(b * b + 1) - b);
        }

        function sinh(n) {
            return (Math.exp(n) - Math.exp(-n)) / 2;
        }

        function cosh(n) {
            return (Math.exp(n) + Math.exp(-n)) / 2;
        }

        function tanh(n) {
            return sinh(n) / cosh(n);
        }

        var r0 = r(0);

        var w = function w(s) {
            return cosh(r0) / cosh(r0 + rho * s);
        };

        var u = function u(s) {
            return w0 * ((cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2) / u1;
        };

        var S = (r(1) - r0) / rho;

        if (Math.abs(u1) < 0.000001 || !isFinite(S)) {
            if (Math.abs(w0 - w1) < 0.000001) return this.animateTo(view, options, step);
            var k = w1 < w0 ? -1 : 1;
            S = Math.abs(Math.log(w1 / w0)) / rho;

            u = function u() {
                return 0;
            };

            w = function w(s) {
                return Math.exp(k * rho * s);
            };
        }

        var renderer = this._getRenderer();

        var framer = function framer(fn) {
            renderer.callInNextFrame(fn);
        };

        var player = this._animPlayer = Animation.animate({
            k: [0, 1]
        }, {
            'easing': options['easing'] || 'out',
            'duration': options['duration'] || 8,
            'framer': framer
        }, function(frame) {
            if (_this2.isRemoved()) {
                player.finish();
                return;
            }

            var k = frame.styles.k;
            var s = k * S;
            var scale = 1 / w(s);
            var props = {};

            if (view.center) {
                var newCenter = k === 1 ? center : from.add(delta.multi(u(s)));
                props.prjCenter = [center, newCenter];
            }

            if (startZoom !== zoom) {
                var newZoom = k === 1 ? zoom : _this2.getZoomForScale(scale, startZoom, true);
                props.zoom = [startZoom, newZoom];
            }

            if (startPitch !== pitch) {
                var newPitch = interpolate$2(startPitch, pitch, k);
                props.pitch = [pitch, newPitch];
            }

            if (startBearing !== bearing) {
                var newBearing = interpolate$2(startBearing, bearing, k);
                props.bearing = [bearing, newBearing];
            }

            if (player.playState === 'running') {
                if (props['prjCenter']) {
                    var _center2 = props['prjCenter'];

                    _this2._setPrjCenter(_center2[1]);

                    _this2.onMoving(_this2._parseEventFromCoord(_this2.getCenter()));
                }

                if (props['zoom']) {
                    _this2.onZooming(props['zoom'][1], zoomOrigin);
                }

                if (props['pitch']) {
                    _this2.setPitch(props['pitch'][1]);
                }

                if (props['bearing']) {
                    _this2.setBearing(props['bearing'][1]);
                }

                _this2._fireEvent('animating');
            } else if (player.playState !== 'paused' || player === _this2._mapAnimPlayer) {
                if (!player._interupted) {
                    if (props['prjCenter']) {
                        _this2._setPrjCenter(props['prjCenter'][1]);
                    }

                    if (props['pitch']) {
                        _this2.setPitch(props['pitch'][1]);
                    }

                    if (props['bearing']) {
                        _this2.setBearing(props['bearing'][1]);
                    }
                }

                _this2._endAnim(player, props, zoomOrigin, options);
            }

            if (step) {
                step(frame);
            }
        });

        this._startAnim({
            center: view.center,
            zoom: view.zoom !== startZoom,
            pitch: pitch !== startPitch,
            bearing: bearing !== startBearing
        }, zoomOrigin);

        return this;
    },
    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();
        }
    }
});

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

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);
        }

        this._fireDOMEvent(this, e, 'dom:' + e.type);

        var mimicClick = false;

        if (type === 'mousedown' || type === 'touchstart' && (!e.touches || 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;
                }
            }
        }

        var mimicEvent;

        if (mimicClick) {
            if (this._clickTime && now() - this._clickTime <= 300) {
                delete this._clickTime;
                mimicEvent = 'dblclick';

                this._fireDOMEvent(this, e, 'dom:dblclick');
            } else {
                this._clickTime = now();
                mimicEvent = 'click';

                this._fireDOMEvent(this, e, 'dom:click');
            }
        }

        if (this._ignoreEvent(e)) {
            return;
        }

        this._fireDOMEvent(this, e, type);

        if (mimicEvent) {
            this._fireDOMEvent(this, e, mimicEvent);
        }
    },
    _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, {
                    'containerPoint': containerPoint,
                    'viewPoint': this.containerPointToViewPoint(containerPoint)
                });

                if (this.getContainerExtent().contains(containerPoint)) {
                    eventParam = extend(eventParam, {
                        'coordinate': this.containerPointToCoord(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$1(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;
}

var RADIAN$1 = Math.PI / 180;
var DEFAULT_FOV = 0.6435011087932844;
var TEMP_COORD$1 = 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$1);

                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);
            }
        };
    }(),
    _pointsToContainerPoints: function() {
        var a = [0, 0, 0];
        return function(points, zoom, altitudes) {
            if (altitudes === void 0) {
                altitudes = [];
            }

            var altitudeIsArray = Array.isArray(altitudes);
            var isTransforming = this.isTransforming();

            var res = this._getResolution(zoom) / this._getResolution();

            var w2 = this.width / 2,
                h2 = this.height / 2;

            var centerPoint = this._prjToPoint(this._getPrjCenter(), undefined, TEMP_COORD$1);

            var pts = [];

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

                var altitude = altitudeIsArray ? altitudes[i] || 0 : altitudes;

                if (isTransforming || altitude) {
                    altitude *= res;
                    var _scale2 = this._glScale;
                    set$2(a, point.x * _scale2, point.y * _scale2, altitude * _scale2);

                    var t = this._projIfBehindCamera(a, this.cameraPosition, this.cameraForward);

                    applyMatrix(t, t, this.projViewMatrix);
                    t[0] = t[0] * w2 + w2;
                    t[1] = -(t[1] * h2) + h2;
                    point.x = t[0];
                    point.y = t[1];
                    pts.push(point);
                } else {
                    var out = point;

                    out._sub(centerPoint.x, centerPoint.y);

                    out.set(out.x, -out.y);
                    pts.push(out._add(w2, h2));
                }
            }

            return pts;
        };
    }(),
    _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(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 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.cameraCenterDistance / 10, 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;
        var y = 4 * cameraCenterDistance;

        if (pitch > 0) {
            pitch = pitch * Math.PI / 180;

            if (2 / Math.PI - pitch > fov / 2) {
                var tanFov = Math.tan(fov / 2);
                var tanP = Math.tan(pitch);
                y = Math.max(cameraCenterDistance * tanFov / (1 / tanP - tanFov), y);
            }
        }

        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$1(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$1(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);
            this.cameraToCenterDistance = distance(this.cameraPosition, this.cameraLookAt);
            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
});

Map$1.include({
    getCollisionIndex: function getCollisionIndex() {
        if (!this._collisionIndex) {
            this.createCollisionIndex();
        }

        return this._collisionIndex || this.createCollisionIndex();
    },
    createCollisionIndex: function createCollisionIndex() {
        this.clearCollisionIndex();
        this._collisionIndex = new CollisionIndex();
        return this._collisionIndex;
    },
    clearCollisionIndex: function clearCollisionIndex() {
        this.collisionFrameTime = 0;

        if (this._collisionIndex) {
            this._collisionIndex.clear();
        }

        return this;
    }
});

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 = [];
        }

        if (this._historyPointer !== undefined && this._vertexes.length > this._historyPointer - 1) {
            this._vertexes.length = this._historyPointer - 1;
        }

        this._vertexes.push({
            label: vertexLabel,
            marker: marker
        });

        this._measureMarkerLayer.addGeometry(marker);

        if (vertexLabel) {
            this._measureMarkerLayer.addGeometry(vertexLabel);
        }
    };

    _proto._msOnDrawEnd = function _msOnDrawEnd(param) {
        this._clearTailMarker();

        if (param['geometry']._getPrjCoordinates().length < 2) {
            this._lastMeasure = 0;

            this._clearMeasureLayers();

            return;
        }

        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;
        }
    };

    _proto._clearMeasureLayers = function _clearMeasureLayers() {
        this._measureLineLayer.remove();

        this._measureMarkerLayer.remove();
    };

    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;

        if (param['point2d']) {
            prjCoord = this.getMap()._pointToPrj(param['point2d']);
        } else {
            var prjCoords = param['geometry']._getPrjCoordinates();

            prjCoords = prjCoords.slice(0, prjCoords.length - 1);

            param['geometry']._setPrjCoordinates(prjCoords);

            prjCoord = prjCoords[prjCoords.length - 1];
        }

        if (param['geometry']._getPrjCoordinates().length < 3) {
            this._lastMeasure = 0;

            this._clearMeasureLayers();

            return;
        }

        var ms = this._measure(param['geometry']);

        var projection = this.getMap().getProjection();
        var coord = projection.unproject(prjCoord);
        var endLabel = new Label(ms, coord, this.options['labelOptions']).addTo(this._measureMarkerLayer);

        endLabel._setPrjCoordinates(prjCoord);

        var size = endLabel.getSize();

        if (!size) {
            size = new Size(10, 10);
        }

        this._addClearMarker(coord, 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 touchstart', 'mousemove touchmove', 'mouseup touchend']
}, 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 touchstart', 'mousemove touchmove', 'mouseup touchend']
}, 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 touchstart', 'mousemove touchmove', 'mouseup touchend']
}, 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 touchstart', 'mousemove touchmove', 'mouseup touchend']
}, 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 touchstart', 'mousemove touchmove', 'mouseup touchend']
}, 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._getViewPoint()._round();

        var mapWidth = map.width;
        var mapHeight = map.height;
        var containerPoint0 = map.viewPointToContainerPoint(point);
        var offset = this.getOffset();
        var containerPoint = containerPoint0.add(offset);

        var prjCoord = map._viewPointToPrj(point);

        var domWidth = parseInt(dom.clientWidth);
        var domHeight = parseInt(dom.clientHeight);
        var margin = 50;
        var left = 0,
            top = 0;

        if (containerPoint.x < 0) {
            left = -containerPoint.x + margin;
        } else if (containerPoint.x + domWidth > mapWidth) {
            left = -(containerPoint.x + domWidth - mapWidth) - margin;
        }

        if (containerPoint.y < 0) {
            top = -containerPoint.y + margin;
        } else if (containerPoint.y + domHeight > mapHeight) {
            top = mapHeight - (containerPoint.y + domHeight) - margin;
        }

        if (top !== 0 || left !== 0) {
            var newContainerPoint = containerPoint0.add(left, top);

            var t = map._containerPointToPoint(newContainerPoint)._sub(map._prjToPoint(map._getPrjCenter()));

            var target = map._pointToPrj(map._prjToPoint(prjCoord).sub(t));

            map._panAnimation(target);
        }
    };

    _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,
    'altitude': 0
};
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.getCenter = function getCenter() {
        return this.getCoordinates();
    };

    _proto.getAltitude = function getAltitude() {
        return this.options.altitude || 0;
    };

    _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;
    };

    _proto._getViewPoint = function _getViewPoint() {
        var alt = 0;

        if (this._owner) {
            var altitude = this.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']);
    };

    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$1 = new Point(0, 0);
var TEMP_POINT3$1 = 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() {
        var size = this.options['tileSize'];

        if (isNumber(size)) {
            size = [size, size];
        }

        return new Size(size);
    };

    _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;
        });

        extent2d._add(offset);

        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, undefined, TEMP_POINT1$1);

        var c;

        if (hasOffset) {
            c = this._project(map._pointToPrj(centerPoint._add(offset), undefined, TEMP_POINT1$1), TEMP_POINT1$1);
        } else {
            c = this._project(prjCenter, TEMP_POINT1$1);
        }

        TEMP_POINT2$1.x = extent2d.xmin;
        TEMP_POINT2$1.y = extent2d.ymax;
        TEMP_POINT3$1.x = extent2d.xmax;
        TEMP_POINT3$1.y = extent2d.ymin;

        var pmin = this._project(map._pointToPrj(TEMP_POINT2$1, undefined, TEMP_POINT2$1), TEMP_POINT2$1);

        var pmax = this._project(map._pointToPrj(TEMP_POINT3$1, undefined, TEMP_POINT3$1), TEMP_POINT3$1);

        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$$1 = this._getTileConfig().tileSystem.scale;

        var tiles = [],
            extent = new PointExtent();

        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,
                        point = _tileInfo.point;
                    p = point;
                } 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$1), 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$1), z, TEMP_POINT3$1);
                    }

                    width = Math.ceil(Math.abs(pp.x - p.x));
                    height = Math.ceil(Math.abs(pp.y - p.y));
                }

                var dx = scale$$1.x * (idx.idx - idx.x) * width,
                    dy = scale$$1.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 (hasOffset) {
                    tileExtent.set(p.x, p.y - height, p.x + width, p.y);

                    tileExtent._sub(offset);
                }

                if (allCount <= 4 || rightVisitEnd || this._isTileInExtent(frustumMatrix, tileExtent, glScale)) {
                    if (this._visitedTiles && cascadeLevel === 0) {
                        this._visitedTiles.add(tileId);
                    }

                    if (cascadeLevel === 0) {
                        tileExtent._add(offset);

                        this._splitTiles(frustumMatrix, tiles, renderer, idx, z + 1, tileExtent, dx, dy, tileOffsets);

                        tileExtent._sub(offset);

                        extent._combine(tileExtent);
                    } else {
                        if (!tileInfo) {
                            tileInfo = {
                                'point': p,
                                'z': z,
                                'x': idx.x,
                                'y': idx.y,
                                'extent2d': tileExtent,
                                'mask': cascadeLevel,
                                'size': [width, height],
                                'id': tileId,
                                'layer': this.getId(),
                                'url': this.getTileUrl(idx.x, idx.y, zoom)
                            };
                        }

                        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);

            tiles.sort(function(a, b) {
                return a.point.distanceTo(center) - b.point.distanceTo(center);
            });
        }

        return {
            'offset': offset,
            'zoom': tileZoom,
            'extent': extent,
            'tiles': tiles
        };
    };

    _proto2._splitTiles = function _splitTiles(frustumMatrix, tiles, renderer, tileIdx, z, tileExtent, dx, dy, tileOffsets) {
        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);

        if (tile) tiles.push(tile);
        tile = this._checkAndAddTile(frustumMatrix, renderer, idx, idy, x, y, z, 0, 1, w, h, corner, glScale, tileOffsets);
        if (tile) tiles.push(tile);
        tile = this._checkAndAddTile(frustumMatrix, renderer, idx, idy, x, y, z, 1, 0, w, h, corner, glScale, tileOffsets);
        if (tile) tiles.push(tile);
        tile = this._checkAndAddTile(frustumMatrix, renderer, idx, idy, x, y, z, 1, 1, w, h, corner, glScale, tileOffsets);
        if (tile) tiles.push(tile);
    };

    _proto2._checkAndAddTile = function _checkAndAddTile(frustumMatrix, renderer, idx, idy, x, y, z, i, j, w, h, corner, glScale, tileOffsets) {
        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);

        childExtent._sub(offset);

        if (!this._isSplittedTileInExtent(frustumMatrix, childExtent, glScale)) {
            return null;
        }

        childExtent._add(offset);

        var tileInfo = renderer && renderer.isTileCachedOrLoading(tileId);

        if (!tileInfo) {
            tileInfo = {
                'point': new Point(childExtent.xmin, childExtent.ymax),
                'z': z,
                'x': x + i,
                'y': y + j,
                'extent2d': childExtent,
                'size': [w, h],
                'id': tileId,
                'layer': this.getId(),
                'url': this.getTileUrl(x + i, y + j, z + this.options['zoomOffset'])
            };
        } 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, glScale) {
        var map = this.getMap();
        var matrix;

        if (frustumMatrix !== map.projViewMatrix) {
            var tileCenter = tileExtent.getCenter(TEMP_POINT6)._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 * glScale;
        TILE_BOX[0][1] = tileExtent.ymin * glScale;
        TILE_BOX[1][0] = tileExtent.xmax * glScale;
        TILE_BOX[1][1] = tileExtent.ymax * glScale;
        return intersectsBox(matrix, TILE_BOX);
    };

    _proto2._isSplittedTileInExtent = function _isSplittedTileInExtent(frustumMatrix, tileExtent, glScale) {
        var map = this.getMap();
        TILE_BOX[0][0] = tileExtent.xmin * glScale;
        TILE_BOX[0][1] = tileExtent.ymin * glScale;
        TILE_BOX[1][0] = tileExtent.xmax * glScale;
        TILE_BOX[1][1] = tileExtent.ymax * 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 options$v = {
    'maxCacheSize': 1024
};

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');
GroupTileLayer.mergeOptions(options$v);

var options$w = {
    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$w.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$w);

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, 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$1(uMatrix, uMatrix, [scale, scale, 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']);
            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) {
            var gl = this.gl;

            var _createProgram2 = createProgram(gl, vert, frag),
                program = _createProgram2.program,
                vertexShader = _createProgram2.vertexShader,
                fragmentShader = _createProgram2.fragmentShader;

            var numUniforms = gl.getProgramParameter(program, 0x8B86);
            var activeUniforms = [];

            for (var i = 0; i < numUniforms; ++i) {
                var info = gl.getActiveUniform(program, i);
                activeUniforms.push(info.name);
            }

            program.vertexShader = vertexShader;
            program.fragmentShader = fragmentShader;

            this._initUniforms(program, activeUniforms);

            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$x = {
    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$x);
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$y = {
    '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$y);
CanvasLayer.registerRenderer('canvas', CanvasLayerRenderer);

var TEMP_POINT$2 = new Point(0, 0);
var options$z = {
    '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$z);
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$A = {
    '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$A);

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 TEMP_POINT$3 = new Point(0, 0);
var TEMP_POINT1$2 = new Point(0, 0);
var TEMP_POINT2$2 = 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;
        }

        this._tileOffsets = {};
        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'];

                if (tile.y === 26771);

                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._drawTileOffset(t.info, t.image);
        });

        placeholders.forEach(function(t) {
            return _this2._drawTileOffset(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._drawTileOffset = function _drawTileOffset(info, image) {
        if (!image) {
            return;
        }

        var offset = this._getTileOffset(info.z);

        if (!offset[0] && !offset[1]) {
            this.drawTile(info, image);
            return;
        }

        info.point._sub(offset);

        info.extent2d._sub(offset);

        this.drawTile(info, image);

        info.point._add(offset);

        info.extent2d._add(offset);
    };

    _proto._drawTileAndCache = function _drawTileAndCache(tile) {
        tile.current = true;
        this.tilesInView[tile.info.id] = tile;

        this._drawTileOffset(tile.info, tile.image);

        this.tileCache.add(tile.info.id, tile);
    };

    _proto._getTileOffset = function _getTileOffset(z) {
        if (!this._tileOffsets[z]) {
            var offset = this.layer._getTileOffset(z);

            this._tileOffsets[z] = offset;
        }

        return this._tileOffsets[z];
    };

    _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 point = tileInfo.point,
            tileZoom = tileInfo.z,
            tileId = tileInfo.id;

        var map = this.getMap(),
            tileSize = tileInfo.size,
            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[0],
            h = tileSize[1];

        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(),
            pmin = layer._project(map._pointToPrj(min, info.z, TEMP_POINT1$2), TEMP_POINT1$2),
            pmax = layer._project(map._pointToPrj(max, info.z, TEMP_POINT2$2), TEMP_POINT2$2);

        var zoomDiff = 2;

        for (var i = 1; i < zoomDiff; i++) {
            this._findChildTilesAt(children, pmin, pmax, layer, info.z + i);
        }

        return children;
    };

    _proto._findChildTilesAt = function _findChildTilesAt(children, pmin, pmax, layer, childZoom) {
        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),
            dmax = layer._getTileConfig().getTileIndex(pmax, res);

        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(),
            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);

            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);
                console.log('_getCachedTile');
                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);

        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 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),
            w = tileInfo.size[0],
            h = tileInfo.size[1];

        if (tileInfo.cache !== false) {
            this._bindGLBuffer(tileImage, w, h);
        }

        if (!this._gl()) {
            _ImageGLRenderable.prototype.drawTile.call(this, tileInfo, tileImage);

            return;
        }

        var point = tileInfo.point;
        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 extent = new Extent(map.pointToCoordinate(tile['point']), map.pointToCoordinate(tile['point'].add(tileSize.toPoint())), map.getProjection());
    this.layer.drawTile(tileCanvas, {
        'url': tile['url'],
        'point': tile['point'],
        'center': map.pointToCoordinate(tile['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 quadVertices = typeof Int8Array !== 'undefined' ? new Int8Array([-1, 1, 0, -1, -1, 0, 1, 1, 0, 1, -1, 0]) : [];
var vert = "\n    attribute vec3 a_position;\n    uniform mat4 transform;\n\n    void main()\n    {\n        gl_Position = transform * vec4(a_position, 1.0);\n    }\n";
var frag = "\n    precision mediump float;\n    uniform vec3 color;\n    void main()\n    {\n        gl_FragColor = vec4(color, 1.0);\n    }\n";

var QuadStencil = function() {
    function QuadStencil(gl, vertices, debug) {
        this.gl = gl;
        this.quadVertices = vertices || quadVertices;
        this.attributes = ['a_position', 3, getType(vertices)];
        this.debug = debug;
    }

    var _proto = QuadStencil.prototype;

    _proto.start = function start() {
        var gl = this.gl;
        gl.enable(gl.STENCIL_TEST);
        gl.stencilMask(0xFF);
        gl.stencilOp(gl.KEEP, gl.REPLACE, gl.REPLACE);
        gl.depthMask(false);

        this._save();

        if (!this.buffer) {
            this._createBuffer();

            this._createProgram();
        }

        gl.useProgram(this.program);
        gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
        enableVertexAttrib(gl, this.program, this.attributes);

        if (!this.transformLoc) {
            this.transformLoc = gl.getUniformLocation(this.program, 'transform');
        }

        if (!this.colorLoc) {
            this.colorLoc = gl.getUniformLocation(this.program, 'color');
        }

        if (this.debug) {
            return;
        }

        gl.colorMask(false, false, false, false);
    };

    _proto.end = function end() {
        var gl = this.gl;
        gl.depthMask(true);

        this._restore();

        if (this.debug) {
            return;
        }

        gl.colorMask(true, true, true, true);
    };

    _proto.draw = function draw(transform) {
        var gl = this.gl;
        gl.uniformMatrix4fv(this.transformLoc, false, transform);
        gl.uniform3fv(this.colorLoc, [Math.random(), Math.random(), Math.random()]);
        gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
    };

    _proto.remove = function remove() {
        var gl = this.gl;

        if (this.buffer) {
            gl.deleteBuffer(this.buffer);
        }

        if (this.program) {
            gl.deleteShader(this.program.fragmentShader);
            gl.deleteShader(this.program.vertexShader);
            gl.deleteProgram(this.program);
        }

        delete this.transformLoc;
        delete this.gl;
        return this;
    };

    _proto.stencilMask = function stencilMask(mask) {
        this.gl.stencilMask(mask);
        return this;
    };

    _proto.stencilFunc = function stencilFunc(func, ref, mask) {
        this.ref = ref;
        this.gl.stencilFunc(func, ref, mask);
        return this;
    };

    _proto.stencilOp = function stencilOp(fail, zfail, zpass) {
        this.gl.stencilOp(fail, zfail, zpass);
        return this;
    };

    _proto.resetFunc = function resetFunc() {
        this.ref = 1;
        this.gl.stencilFunc(this.gl.ALWAYS, 1, 0xFF);
        return this;
    };

    _proto._save = function _save() {
        var gl = this.gl;
        this._savedProgram = gl.program;
    };

    _proto._restore = function _restore() {
        var gl = this.gl;
        gl.program = this._savedProgram;

        if (gl.program) {
            gl.useProgram(gl.program);
        }
    };

    _proto._createBuffer = function _createBuffer() {
        var gl = this.gl;
        this.buffer = gl.createBuffer();

        if (!this.buffer) {
            throw new Error('Failed to create the buffer object');
        }

        gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
        gl.bufferData(gl.ARRAY_BUFFER, this.quadVertices, gl.STATIC_DRAW);
    };

    _proto._createProgram = function _createProgram() {
        var _createProgram2 = createProgram(this.gl, vert, frag),
            program = _createProgram2.program,
            vertexShader = _createProgram2.vertexShader,
            fragmentShader = _createProgram2.fragmentShader;

        program.vertexShader = vertexShader;
        program.fragmentShader = fragmentShader;
        this.program = program;
    };

    return QuadStencil;
}();

function getType(arr) {
    if (arr instanceof Float32Array) {
        return 'FLOAT';
    } else if (arr instanceof Int16Array) {
        return 'SHORT';
    } else if (arr instanceof Uint16Array) {
        return 'UNSIGNED_SHORT';
    } else if (arr instanceof Int8Array) {
        return 'BYTE';
    } else if (arr instanceof Uint8Array || arr instanceof Uint8ClampedArray) {
        return 'UNSIGNED_BYTE';
    }

    return 'FLOAT';
}

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 TEMP_VEC3 = [];
var TEMP_FIXEDEXTENT = new PointExtent();
var PLACEMENT_CENTER = 'center';
var TEMP_POINTS = [];
var TEMP_ALTITUDES = [];
var TEMP_GEOS = [];

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._updateMapStateCache();

        this._updateDisplayExtent();

        var map = this.getMap();
        var count = this.layer.getCount();
        var res = this.mapStateCache.resolution;

        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._batchConversionMarkers(this.mapStateCache.glZoom);

            this.forEachGeo(this.checkGeo, this);
            this._drawnRes = res;
        }

        this._sortByDistanceToCamera(map.cameraPosition);

        for (var i = 0, l = this._geosToDraw.length; i < l; i++) {
            var geo = this._geosToDraw[i];

            if (!geo._isCheck) {
                if (!geo.isVisible()) {
                    delete geo._cPoint;
                    delete geo._inCurrentView;
                    continue;
                }
            }

            geo._paint(this._displayExtent);

            delete this._geosToDraw[i]._cPoint;
            delete this._geosToDraw[i]._inCurrentView;
        }
    };

    _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._updateMapStateCache();

        this._drawnRes = this.mapStateCache.resolution;

        this._updateDisplayExtent();

        this.prepareToDraw();

        this._batchConversionMarkers(this.mapStateCache.glZoom);

        this.forEachGeo(this.checkGeo, this);

        this._sortByDistanceToCamera(this.getMap().cameraPosition);

        for (var i = 0, len = this._geosToDraw.length; i < len; i++) {
            this._geosToDraw[i]._paint();

            delete this._geosToDraw[i]._cPoint;
            delete this._geosToDraw[i]._inCurrentView;
        }
    };

    _proto.prepareToDraw = function prepareToDraw() {
        this._hasPoint = false;
        this._geosToDraw = [];
    };

    _proto.checkGeo = function checkGeo(geo) {
        geo._isCheck = false;

        if (!geo || !geo.isVisible() || !geo.getMap() || !geo.getLayer() || !geo.getLayer().isCanvasRender()) {
            return;
        }

        var painter = geo._getPainter();

        var inCurrentView = true;

        if (geo._inCurrentView) {
            inCurrentView = true;
        } else if (geo._inCurrentView === false) {
            inCurrentView = false;
        } else {
            var extent2D = painter.get2DExtent(this.resources, TEMP_EXTENT$4);

            if (!extent2D || !extent2D.intersects(this._displayExtent)) {
                inCurrentView = false;
            }
        }

        if (!inCurrentView) {
            return;
        }

        if (painter.hasPoint()) {
            this._hasPoint = true;
        }

        geo._isCheck = 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);
    };

    _proto._updateMapStateCache = function _updateMapStateCache() {
        var map = this.getMap();

        var offset = map._pointToContainerPoint(this.southWest)._add(0, -map.height);

        var resolution = map.getResolution();
        var pitch = map.getPitch();
        var bearing = map.getBearing();
        var glScale = map.getGLScale();
        var glZoom = map.getGLZoom();
        var containerExtent = map.getContainerExtent();

        var _2DExtent = map._get2DExtent();

        var glExtent = map._get2DExtent(glZoom);

        this.mapStateCache = {
            resolution: resolution,
            pitch: pitch,
            bearing: bearing,
            glScale: glScale,
            glZoom: glZoom,
            _2DExtent: _2DExtent,
            glExtent: glExtent,
            containerExtent: containerExtent,
            offset: offset
        };
        return this;
    };

    _proto._batchConversionMarkers = function _batchConversionMarkers(glZoom) {
        TEMP_ALTITUDES.length = TEMP_GEOS.length = TEMP_POINTS.length = 0;
        var altitudeCache = {};
        var idx = 0;

        for (var i = 0, len = this.layer._geoList.length; i < len; i++) {
            var geo = this.layer._geoList[i];
            var type = geo.getType();

            if (type === 'Point') {
                var painter = geo._painter;

                if (!painter) {
                    continue;
                }

                var point = painter.getRenderPoints(PLACEMENT_CENTER)[0][0];
                var altitude = geo.getAltitude();

                if (altitudeCache[altitude] == null) {
                    altitudeCache[altitude] = painter.getAltitude();
                }

                TEMP_POINTS[idx] = point;
                TEMP_ALTITUDES[idx] = altitudeCache[altitude];
                TEMP_GEOS[idx] = geo;
                idx++;
            }
        }

        if (idx === 0) {
            return [];
        }

        var map = this.getMap();

        var pts = map._pointsToContainerPoints(TEMP_POINTS, glZoom, TEMP_ALTITUDES);

        var containerExtent = map.getContainerExtent();
        var xmax = containerExtent.xmax,
            ymax = containerExtent.ymax,
            xmin = containerExtent.xmin,
            ymin = containerExtent.ymin;
        var symbolkeyMap = {};

        for (var _i = 0, _len = TEMP_GEOS.length; _i < _len; _i++) {
            var _geo = TEMP_GEOS[_i];
            _geo._cPoint = pts[_i];
            var _pts$_i = pts[_i],
                x = _pts$_i.x,
                y = _pts$_i.y;
            _geo._inCurrentView = x >= xmin && y >= ymin && x <= xmax && y <= ymax;

            if (!_geo._inCurrentView) {
                var symbolkey = _geo.__symbol;
                var fixedExtent = void 0;

                if (symbolkey) {
                    fixedExtent = symbolkeyMap[symbolkey] = symbolkeyMap[symbolkey] || _geo._painter.getFixedExtent();
                } else {
                    fixedExtent = _geo._painter.getFixedExtent();
                }

                TEMP_FIXEDEXTENT.set(fixedExtent.xmin, fixedExtent.ymin, fixedExtent.xmax, fixedExtent.ymax);

                TEMP_FIXEDEXTENT._add(pts[_i]);

                _geo._inCurrentView = TEMP_FIXEDEXTENT.intersects(containerExtent);
            }
        }

        return pts;
    };

    _proto._sortByDistanceToCamera = function _sortByDistanceToCamera(cameraPosition) {
        if (!this.layer.options['sortByDistanceToCamera']) {
            return;
        }

        if (!this._geosToDraw.length) {
            return;
        }

        var map = this.getMap();
        var p = map.distanceToPoint(1000, 0, map.getGLScale()).x;
        var meterScale = p / 1000;
        var placement = 'center';

        this._geosToDraw.sort(function(a, b) {
            var type0 = a.getType();
            var type1 = b.getType();

            if (type0 !== 'Point' || type1 !== 'Point') {
                return 0;
            }

            var painter0 = a._painter;
            var painter1 = b._painter;

            if (!painter0 || !painter1) {
                return 0;
            }

            var point0 = painter0.getRenderPoints(placement)[0][0];
            var point1 = painter1.getRenderPoints(placement)[0][0];
            var alt0 = painter0.getAltitude() * meterScale;
            var alt1 = painter1.getAltitude() * meterScale;
            set$2(TEMP_VEC3, point0.x, point0.y, alt0);
            var dist0 = distance(TEMP_VEC3, cameraPosition);
            set$2(TEMP_VEC3, point1.x, point1.y, alt1);
            var dist1 = distance(TEMP_VEC3, cameraPosition);
            return dist1 - dist0;
        });
    };

    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();
        map.clearCollisionIndex();

        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, quality) {
        if (!this.canvas) {
            return null;
        }

        return this.canvas.toDataURL(mimeType, quality);
    };

    _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;
        }

        if (this.map.options['renderable']) {
            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,
    QuadStencil: QuadStencil,
    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);

var TEMP_WITHIN = {
    within: false,
    center: [0, 0]
};

function isWithinPixel(painter) {
    if (!painter || !painter.__bbox) {
        TEMP_WITHIN.within = false;
    } else {
        TEMP_WITHIN.within = false;
        var _painter$__bbox = painter.__bbox,
            minx = _painter$__bbox.minx,
            miny = _painter$__bbox.miny,
            maxx = _painter$__bbox.maxx,
            maxy = _painter$__bbox.maxy;
        var offsetx = Math.abs(maxx - minx);
        var offsety = Math.abs(maxy - miny);

        if (offsetx <= 1 && offsety <= 1) {
            TEMP_WITHIN.within = true;
            TEMP_WITHIN.center[0] = (minx + maxx) / 2;
            TEMP_WITHIN.center[1] = (miny + maxy) / 2;
        }

        delete painter.__bbox;
    }

    return TEMP_WITHIN;
}

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) {
        var r = isWithinPixel(this._painter);

        if (r.within) {
            Canvas.pixelRect(ctx, r.center, lineOpacity, fillOpacity);
        } else 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) {
        var r = isWithinPixel(this._painter);

        if (r.within) {
            Canvas.pixelRect(ctx, r.center, lineOpacity, fillOpacity);
        } else {
            Canvas.polygon(ctx, points, lineOpacity, fillOpacity, dasharray, this.options['smoothness']);
        }
    }
});

var adapters = {};

function registerWorkerAdapter(workerKey, adapter) {
    adapters[workerKey] = adapter;
}
var header = "\n    var adapters = {};\n    onmessage = function (msg) {\n        msg = msg.data;\n        var workerKey = msg.workerKey;\n        var adapter = adapters[workerKey];\n        if (!adapter) {\n            post(msg.callback, 'Unregistered worker adapters for ' + workerKey);\n            return;\n        }\n        try {\n            adapter.onmessage(msg, wrap(msg.callback));\n        } catch (err) {\n            post(msg.callback, workerKey + ':' + err.message);\n            console.error(err);\n            throw err;\n        }\n    };\n    function post(callback, err, data, buffers) {\n        var msg = {\n            callback : callback\n        };\n        if (err) {\n            msg.error = err;\n        } else {\n            msg.data = data;\n        }\n        if (buffers && buffers.length > 0) {\n            postMessage(msg, buffers);\n        } else {\n            postMessage(msg);\n        }\n    }\n    function wrap(callback) {\n        return function (err, data, buffers) {\n            post(callback, err, data, buffers);\n        };\n    }\n    var workerExports;\n";
var footer = "\n    workerExports = null;\n";

function compileWorkerSource() {
    var source = header;

    for (var p in adapters) {
        var adapter = adapters[p];
        source += "\n    workerExports = {};\n    (" + adapter + ")(workerExports, self);\n    adapters['" + p + "'] = workerExports";
        source += "\n    workerExports.initialize && workerExports.initialize(self);\n        ";
    }

    source += footer;
    return source;
}

var url;

function getWorkerSourcePath() {
    if (typeof window === 'undefined') {
        return null;
    }

    if (!url) {
        var source = compileWorkerSource();
        url = window.URL.createObjectURL(new Blob([source], {
            type: 'text/javascript'
        }));
        adapters = null;
    }

    return url;
}

var hardwareConcurrency = typeof window !== 'undefined' ? window.navigator.hardwareConcurrency || 4 : 0;
var workerCount = Math.max(Math.floor(hardwareConcurrency / 2), 1);

var WorkerPool = function() {
    function WorkerPool() {
        this.active = {};
        this.workerCount = typeof window !== 'undefined' ? window.MAPTALKS_WORKER_COUNT || workerCount : 0;
    }

    var _proto = WorkerPool.prototype;

    _proto.acquire = function acquire(id) {
        if (!this.workers) {
            this.workers = [];
            var url = getWorkerSourcePath();

            for (var i = 0; i < this.workerCount; i++) {
                var worker = new Worker(url);
                worker.id = i;
                this.workers.push(worker);
            }
        }

        this.active[id] = true;
        return this.workers.slice();
    };

    _proto.release = function release(id) {
        delete this.active[id];

        if (Object.keys(this.active).length === 0) {
            this.workers.forEach(function(w) {
                w.terminate();
            });
            this.workers = null;
        }
    };

    return WorkerPool;
}();
var globalWorkerPool;

function getGlobalWorkerPool() {
    if (!globalWorkerPool) {
        globalWorkerPool = new WorkerPool();
    }

    return globalWorkerPool;
}

var dedicatedWorker = 0;
var EMPTY_BUFFERS = [];

var Actor = function() {
    function Actor(workerKey) {
        var _this = this;

        this.workerKey = workerKey;
        this.workerPool = getGlobalWorkerPool();
        this.currentActor = 0;
        this.actorId = UID();
        this.workers = this.workerPool.acquire(this.actorId);
        this.callbacks = {};
        this.callbackID = 0;
        this.receiveFn = this.receive.bind(this);
        this.workers.forEach(function(w) {
            w.addEventListener('message', _this.receiveFn, false);
        });
    }

    var _proto = Actor.prototype;

    _proto.isActive = function isActive() {
        return !!this.workers;
    };

    _proto.broadcast = function broadcast(data, buffers, cb) {
        var _this2 = this;

        cb = cb || function() {};

        asyncAll(this.workers, function(worker, done) {
            _this2.send(data, buffers, done, worker.id);
        }, cb);
        return this;
    };

    _proto.send = function send(data, buffers, cb, workerId) {
        var id = cb ? this.actorId + ":" + this.callbackID++ : null;
        if (cb) this.callbacks[id] = cb;
        this.post({
            data: data,
            callback: String(id)
        }, buffers, workerId);
        return this;
    };

    _proto.receive = function receive(message) {
        var _this3 = this;

        var data = message.data,
            id = data.callback;
        var callback = this.callbacks[id];
        delete this.callbacks[id];

        if (data.type === '<request>') {
            if (this.actorId === data.actorId) {
                this[data.command](data.params, function(err, cbData, buffers) {
                    var message = {
                        type: '<response>',
                        callback: data.callback
                    };

                    if (err) {
                        message.error = err.message;
                    } else {
                        message.data = cbData;
                    }

                    _this3.post(message, buffers || EMPTY_BUFFERS, data.workerId);
                });
            }
        } else if (callback && data.error) {
            callback(data.error);
        } else if (callback) {
            callback(null, data.data);
        }
    };

    _proto.remove = function remove() {
        var _this4 = this;

        this.workers.forEach(function(w) {
            w.removeEventListener('message', _this4.receiveFn, false);
        });
        this.workerPool.release(this.actorId);
        delete this.receiveFn;
        delete this.workers;
        delete this.callbacks;
        delete this.workerPool;
    };

    _proto.post = function post(data, buffers, targetID) {
        if (typeof targetID !== 'number' || isNaN(targetID)) {
            targetID = this.currentActor = (this.currentActor + 1) % this.workerPool.workerCount;
        }

        data.workerId = targetID;
        data.workerKey = this.workerKey;
        data.actorId = this.actorId;
        this.workers[targetID].postMessage(data, buffers || EMPTY_BUFFERS);
        return targetID;
    };

    _proto.getDedicatedWorker = function getDedicatedWorker() {
        dedicatedWorker = (dedicatedWorker + 1) % this.workerPool.workerCount;
        return dedicatedWorker;
    };

    return Actor;
}();

function asyncAll(array, fn, callback) {
    if (!array.length) {
        callback(null, []);
    }

    var remaining = array.length;
    var results = new Array(array.length);
    var error = null;
    array.forEach(function(item, i) {
        fn(item, function(err, result) {
            if (err) error = err;
            results[i] = result;
            if (--remaining === 0) callback(error, results);
        });
    });
}

Map$1.VERSION = version;
var worker = {
    Actor: Actor
};

export { index$1 as Util, dom as DomUtil, strings as StringUtil, index as MapboxUtil, Map$1 as Map, index$4 as ui, index$5 as control, index$6 as renderer, index$3 as symbolizer, Animation$1 as animation, worker, Browser$1 as Browser, LRUCache, Ajax, Canvas, Promise$1 as Promise, Class, Eventable, JSONAble, CollisionIndex, Handlerable, Handler$1 as Handler, DragHandler, MapTool, DrawTool, AreaTool, DistanceTool, SpatialReference, registerWorkerAdapter, INTERNAL_LAYER_PREFIX, GEOMETRY_COLLECTION_TYPES, GEOJSON_TYPES, RESOURCE_PROPERTIES, RESOURCE_SIZE_PROPERTIES, NUMERICAL_PROPERTIES, COLOR_PROPERTIES, DEFAULT_TEXT_SIZE, projections as projection, index$2 as measurer, Coordinate, CRS, Extent, Point, PointExtent, Size, Transformation, Layer, TileLayer, GroupTileLayer, WMSTileLayer, CanvasTileLayer, ImageLayer, OverlayLayer, VectorLayer, CanvasLayer, ParticleLayer, TileSystem, TileConfig, ArcCurve, Circle, ConnectorLine, ArcConnectorLine, CubicBezierCurve, Curve, Ellipse, GeoJSON, Geometry, GeometryCollection, Label, LineString, Marker, MultiLineString, MultiPoint, MultiPolygon, Polygon, QuadBezierCurve, Rectangle, Sector, TextBox, TextMarker };